Apakah "git export" (seperti "svn export")?

2356

Saya telah bertanya-tanya apakah ada solusi "git export" yang baik yang membuat salinan pohon tanpa .gitdirektori repositori. Setidaknya ada tiga metode yang saya tahu:

  1. git clonediikuti dengan menghapus .gitdirektori repositori.
  2. git checkout-index menyinggung fungsi ini tetapi dimulai dengan "Baca saja pohon yang diinginkan ke dalam indeks ..." yang saya tidak sepenuhnya yakin bagaimana melakukannya.
  3. git-exportadalah skrip pihak ketiga yang pada dasarnya melakukan a git cloneke lokasi sementara diikuti oleh rsync --exclude='.git'ke tujuan akhir.

Tak satu pun dari solusi ini yang menurut saya memuaskan. Yang terdekat svn exportmungkin adalah opsi 1, karena keduanya memerlukan direktori target menjadi kosong terlebih dahulu. Tetapi opsi 2 tampaknya lebih baik, dengan asumsi saya bisa mencari tahu apa artinya membaca pohon ke dalam indeks.

Greg Hewgill
sumber
1
@rnrTom: Lihat jawaban Somov. (tidak ada yang "dikompresi" dalam arsip tar).
etarion
23
@mrTom git archive --format zip --output "output.zip" master -0akan memberi Anda arsip yang tidak terkompresi (-0 adalah bendera untuk yang tidak terkompresi). git-scm.com/docs/git-archive .
7
Saya setuju dengan @mrTom, dan saya tidak berpikir apakah arsip dikompresi atau tidak dikompresi adalah masalah utama. Dengan SVN, saya dapat exportsubdirektori 250 kB langsung dari repositori jarak jauh (yang bisa berukuran 200 MB, tidak termasuk revisi) - dan saya hanya akan menekan jaringan untuk transfer unduhan 250 kB (atau lebih). Dengan git, archiveharus diaktifkan di server (jadi saya tidak bisa mencobanya) - clone --depth 1dari server masih dapat mengambil repo katakanlah 25 MB, di mana .gitsubfolder sendiri membutuhkan 15MB. Karena itu, saya masih mengatakan jawabannya "tidak".
sdaau
@ MrTom jawabannya sebenarnya YA Lihat jawaban OP - perintahnya adalahgit checkout-index
nocache
Ini cara yang bagus dan sederhana:git archive -o latest.zip HEAD
Evgeni Sergeev

Jawaban:

2397

Mungkin cara paling sederhana untuk mencapai ini adalah dengan git archive. Jika Anda benar-benar membutuhkan hanya pohon yang diperluas, Anda dapat melakukan sesuatu seperti ini.

git archive master | tar -x -C /somewhere/else

Sebagian besar waktu saya perlu 'mengekspor' sesuatu dari git, saya ingin arsip terkompresi dalam hal apa pun jadi saya melakukan sesuatu seperti ini.

git archive master | bzip2 >source-tree.tar.bz2

Arsip ZIP:

git archive --format zip --output /full/path/to/zipfile.zip master 

git help archive untuk lebih jelasnya cukup fleksibel.


Ketahuilah bahwa meskipun arsip tidak akan berisi direktori .git, namun, arsip itu akan berisi file tersembunyi khusus git seperti .gitignore, .gitattributes, dll. Jika Anda tidak menginginkannya di arsip, pastikan Anda gunakan atribut ekspor-abaikan dalam file .gitattributes dan lakukan ini sebelum melakukan arsip Anda. Baca lebih banyak...


Catatan: Jika Anda tertarik untuk mengekspor indeks, perintahnya adalah

git checkout-index -a -f --prefix=/destination/path/

(Lihat jawaban Greg untuk lebih jelasnya)

CB Bailey
sumber
198
Arsip ZIP:git archive --format zip --output /full/path master
Vadim
221
Ketahuilah bahwa arsip tidak akan berisi direktori .git, tetapi akan berisi file tersembunyi spesifik git lainnya seperti .gitignore, .gitattributes, dll. Jadi jika Anda tidak menginginkannya, pastikan Anda menggunakan atribut ekspor-abaikan di file .gitattributes dan lakukan ini sebelum melakukan arsip Anda. Lihat feeding.cloud.geek.nz/2010/02/...
mj1531
54
Untuk menindaklanjuti catatan Streams ': Anda dapat menambahkan string' --prefix = something / 'ke perintah untuk mengontrol nama direktori yang akan dikemas di dalam zip. Misalnya, jika Anda menggunakan git archive --format zip --output /path/to/file.zip --prefix=newdir/ masteroutput akan disebut 'file.zip' tetapi ketika Anda membukanya, direktori tingkat atas akan menjadi 'newdir'. (Jika Anda menghilangkan atribut --prefix, direktori level atas adalah 'file'.)
Alan W. Smith
89
Cara termudah: git archive -o latest.zip HEADIni membuat arsip Zip yang berisi isi dari komit terbaru pada cabang saat ini. Perhatikan bahwa format output disimpulkan oleh ekstensi file output.
nacho4d
37
Itu tidak mendukung git submodules :(
umpirsky
320

Saya menemukan apa artinya opsi 2. Dari repositori, Anda dapat melakukan:

git checkout-index -a -f --prefix=/destination/path/

Slash pada akhir path penting, jika tidak maka akan menghasilkan file / tujuan dengan awalan 'path'.

Karena dalam situasi normal indeks berisi isi repositori, tidak ada yang istimewa untuk dilakukan "membaca pohon yang diinginkan ke dalam indeks". Sudah ada di sana.

The -aflag diperlukan untuk memeriksa semua file dalam indeks (saya tidak yakin apa artinya untuk menghilangkan bendera ini dalam situasi ini, karena tidak melakukan apa yang saya inginkan). The -fpasukan bendera Timpa file yang ada dalam output, yang perintah ini tidak biasanya melakukan.

Tampaknya ini semacam "ekspor git" yang saya cari.

Greg Hewgill
sumber
73
... dan JANGAN LUPA SLASH DI AKHIR, atau Anda tidak akan memiliki efek yang diinginkan;)
conny
1
The git addperintah mengubah konten dalam indeks, sehingga apa pun yang git statusmenunjukkan sebagai "berkomitmen" adalah perbedaan antara KEPALA dan isi indeks.
Greg Hewgill
7
@conny: baca komentar Anda, lupakan dan jalankan perintah tanpa garis miring. tip: ikuti saran conny -.-
Znarkus
35
Beri +1 pada saran conny. Juga, jangan mencoba membuat '~ / dest /', karena ini membuat direktori yang disebut '~' di direktori kerja Anda, daripada apa yang Anda inginkan. Coba tebak apa yang terjadi ketika Anda mengetik rm -rf ~
Kyle Heironimus
5
@KyleHeironimus - peringatan Anda tentang penggunaan '~ / dest / `benar jika Anda menggunakan tanda kutip di sekitar jalur awalan Anda yang memberi tahu shell untuk tidak melakukan ekspansi tilde. Sebuah dir yang disebut ~(tidak '~'!) Akan dibuat di dir yang berfungsi. Tidak ada yang istimewa git checkout-indexdalam hal ini: Hal yang sama berlaku untuk mkdir '~/dest'( jangan lakukan itu! ). Namun alasan lain yang baik untuk menghindari nama file yang perlu dikutip (misalnya yang memiliki spasi di dalamnya) :-)
Matt Wallis
254

git archive juga bekerja dengan repositori jarak jauh.

git archive --format=tar \
--remote=ssh://remote_server/remote_repository master | tar -xf -

Untuk mengekspor path tertentu di dalam repo, tambahkan path sebanyak yang Anda inginkan sebagai argumen terakhir ke git, misalnya:

git archive --format=tar \
--remote=ssh://remote_server/remote_repository master path1/ path2/ | tar -xv
Alexander Somov
sumber
6
Pilihan ini adalah yang paling saya sukai. Ini memiliki manfaat tambahan yang juga berfungsi pada repositori kosong.
innaM
5
Versi yang ditingkatkan adalah: git archive --format=tar --prefix=PROJECT_NAME/ --remote=USER@SERVER:PROJECT_NAME.git master | tar -xf - (memastikan arsip Anda ada di folder)
Nick
7
Catatan : server harus mengaktifkan fitur ini.
Jakub Narębski
12
Saya mencoba: git archive --format=zip --output foo.zip --remote=https://github.com/xxx.git masterDan menjadi fatal: Operasi tidak didukung oleh protokol. Akhir dari aliran perintah yang tidak terduga.
andyf
7
@andyf GitHub memiliki caranya sendiri: curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | tar xzf -per dokumen
uskup
63

masukkan deskripsi gambar di sini

Jawaban kasus khusus jika repositori di-host di GitHub.

Gunakan saja svn export.

Sejauh yang saya tahu Github tidak mengizinkan archive --remote. Meskipun GitHub kompatibel dengan svn dan mereka memiliki semua repositori git svndapat diakses sehingga Anda bisa menggunakannya svn exportseperti biasanya dengan beberapa penyesuaian pada url GitHub Anda.

Misalnya untuk mengekspor seluruh repositori, perhatikan bagaimana trunkURL menggantikan master(atau apa pun cabang HEAD proyek diatur ke ):

svn export https://github.com/username/repo-name/trunk/

Dan Anda dapat mengekspor satu file atau bahkan path atau folder tertentu:

svn export https://github.com/username/repo-name/trunk/src/lib/folder

Contoh dengan jQuery JavaScript Library

The HEADcabang atau Master cabang akan menggunakan tersedia trunk:

svn ls https://github.com/jquery/jquery/trunk

Non- HEAD cabang akan dapat diakses di bawah /branches/:

svn ls https://github.com/jquery/jquery/branches/2.1-stable

Semua tag dengan /tags/cara yang sama:

svn ls https://github.com/jquery/jquery/tags/2.1.3
Anthony Hatzopoulos
sumber
1
git archiveberfungsi baik dengan GitHub, selama Anda menggunakan protokol git, Cukup ganti https://dengan git://di URL. Saya tidak tahu mengapa GitHub tidak mengiklankan fitur tersembunyi ini.
Neil Mayhew
1
@NeilMayhew Saya tidak mengerti fatal: The remote end hung up unexpectedly. Mencoba di dua server berbeda dengan repo jQuery github.
Anthony Hatzopoulos
1
Kamu benar. Saya lupa bahwa saya sedang menggunakan git config url.<base>.insteadOfcache repositori jarak jauh. Karena itu saya menggunakan file://URL pada kenyataannya. Saya ragu apakah itu git archivebisa berfungsi dengan git://URL karena harus dapat berjalan git-upload-archivedi ujung yang jauh. Seharusnya dimungkinkan menggunakan sshprotokol, kecuali bahwa github tidak mengizinkannya ( Invalid command: 'git-upload-archive').
Neil Mayhew
Adakah cara untuk menggunakan alat server lokal yang berperilaku seperti github jika saya ingin melakukannya di repositori git yang dihosting secara internal?
Kriss
1
terbalik - benar-benar aneh bahwa Git tidak memiliki fitur ini dan kami harus menggunakan svn
Jason S
40

Dari Manual Git :

Menggunakan git-checkout-index untuk "mengekspor seluruh pohon"

Kemampuan awalan pada dasarnya membuatnya sepele untuk menggunakan git-checkout-index sebagai fungsi "ekspor sebagai pohon". Baca saja pohon yang diinginkan ke dalam indeks, dan lakukan:

$ git checkout-index --prefix=git-export-dir/ -a

jperras
sumber
19
Saya pikir kebingungannya adalah frasa "baca pohon yang diinginkan ke dalam indeks".
davetron5000
4
Jika Anda ingin mengekspor direktori foo di branch bar, maka ini akan menjadi git read-tree bar:fooDan kemudian git checkout-index --prefix=export_dir/ -asetelah itu mungkin Anda harus melakukannyagit update-index master
Pascal Rosin
1
@ JohnWeldon Apakah Anda harus mengkloning repo terlebih dahulu? Jika demikian, maka saya tidak akan menerimanya, karena seluruh poin "ekspor svn" dari subdirektori adalah untuk secara langsung mendapatkan salinan subdirektori itu; jika seseorang memiliki repo Git 1GB dan yang saya inginkan adalah subdirektori 10kB, itu gila untuk meminta saya mengkloning semuanya.
Jason S
3
Juga saya akan echo @ davetron5000 dengan komentar "baca pohon yang diinginkan ke dalam indeks" yang saya tidak tahu apa artinya.
Jason S
38

Saya telah menulis pembungkus sederhana git-checkout-indexyang dapat Anda gunakan seperti ini:

git export ~/the/destination/dir

Jika direktori tujuan sudah ada, Anda harus menambahkan -fatau --force.

Instalasi sederhana; cukup letakkan script di suatu tempat di Anda PATH, dan pastikan itu dapat dieksekusi.

Repositori github untuk git-export

Daniel Schierbeck
sumber
15
Wrapper ini bukan platform-agnostik; ini bergantung pada / bin / sh. Jadi, jika Anda menggunakan Windows, solusi ini mungkin tidak cocok untuk Anda.
shovavnik
18
Uhh, skrip ini terdiri dari 57 baris dokumentasi, spasi putih, pengaturan, penguraian argumen, dan hanya satu baris yang benar-benar melakukan sesuatu ...
Vladimir Panteleev
36

Tampaknya ini bukan masalah dengan Git daripada SVN. Git hanya menempatkan folder .git di root repositori, sedangkan SVN menempatkan folder .svn di setiap subdirektori. Jadi "ekspor svn" menghindari sihir baris perintah rekursif, sedangkan dengan rekursi Git tidak diperlukan.

Kostmo
sumber
26
Pada SVN 1.7, hanya ada satu folder .svn: subversion.apache.org/docs/release-notes/1.7.html#single-db
kostmo
Ini tidak akan menyingkirkan file bangunan tambahan apa pun yang dihapus oleh ekspor. Jadi ini jelas bukan jawabannya.
ygoe
28

Setara dengan

svn export . otherpath

di dalam repo yang ada adalah

git archive branchname | (cd otherpath; tar x)

Setara dengan

svn export url otherpath

adalah

git archive --remote=url branchname | (cd otherpath; tar x)
aredridel
sumber
1
terima kasih, ini adalah apa yang saya lewatkan ... juga, untuk memeriksa stempel waktu ekspor (mereka tidak akan disimpan seperti pada file), gunakan git archive --format=tar --prefix=junk/ HEAD | (tar -t -v --full-time -f -)... Namun, pengarsipan dengan stempel waktu tidak sepenuhnya sepele, jadi saya memposting contoh di bawah ini .
sdaau
1
Anda dapat menggunakan opsi C untuk tar bukan subkulit, seperti ini: git archive branchname | tar xC otherpath
James Moore
Ke atas bahwa Copsi untuk tar adalah GNU Tar saja.
aredridel
22

Jika Anda tidak termasuk file dengan .gitattributes export-ignoremaka cobagit checkout

mkdir /path/to/checkout/
git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout -f -q

-f
Saat memeriksa jalur dari indeks, jangan gagal pada entri yang tidak di-emergasi; sebagai gantinya, entri yang tidak dihapus diabaikan.

dan

-q
Hindari verbose

Selain itu Anda bisa mendapatkan Cabang atau Tag atau dari Revisi Komit tertentu seperti di SVN hanya menambahkan SHA1 (SHA1 di Git adalah setara dengan Nomor Revisi di SVN)

mkdir /path/to/checkout/
git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout 2ef2e1f2de5f3d4f5e87df7d8 -f -q -- ./

The /path/to/checkout/harus kosong, Git tidak akan menghapus file apapun, tetapi akan menimpa file-file dengan nama yang sama tanpa peringatan

PEMBARUAN: Untuk menghindari masalah pemenggalan kepala atau meninggalkan repositori yang berfungsi saat menggunakan checkout untuk ekspor dengan tag, cabang atau SHA1, Anda perlu menambahkan -- ./di bagian akhir

Tanda hubung ganda --memberitahu git bahwa segala sesuatu setelah tanda hubung adalah path atau file, dan juga dalam hal ini memberitahu git checkoutuntuk tidak mengubahHEAD

Contoh:

Perintah ini hanya akan mendapatkan direktori libs dan juga readme.txtfile dari commit tersebut

git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout fef2e1f2de5f3d4f5e87df7d8 -f -q -- ./libs ./docs/readme.txt

Ini akan membuat (menimpa) my_file_2_behind_HEAD.txtdua komit di belakang kepalaHEAD^2

git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout HEAD^2 -f -q -- ./my_file_2_behind_HEAD.txt

Untuk mendapatkan ekspor cabang lain

git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout myotherbranch -f -q -- ./

Perhatikan bahwa ./itu relatif terhadap akar repositori

pengguna5286776117878
sumber
Sebenarnya, di antara banyak lainnya dan upvotes, ini bekerja paling baik untuk saya, tanpa kompresi, bekerja dengan baik dengan repositori telanjang (gitolite).
Takeshin
1
Perhatikan bahwa checkout SHA1 akan menciptakan masalah "pemenggalan" di repositori
user5286776117878
sebenarnya @ITGabs, ini tidak mengunduh folder ".git". Jadi folder yang diunduh bukan repositori git, sehingga tidak secara teknis "dipenggal"
Fabio Marreco
@FabioMarreco Masalah pemenggalan adalah pada repositori yang tidak ada dalam file yang diekspor / diunduh, saya memperbarui jawabannya untuk lebih jelasnya
user5286776117878
3
Ini bekerja baik untuk saya. Tetapi pada awalnya saya mendapat pesan kesalahan "Not a git repository". Kemudian saya menemukan bahwa "/ path / to / repo /" harus menunjuk ke folder .git. Jadi ini berhasil: --git-dir = / path / to / repo / .git
philburk
21

Saya menggunakan git-submodules secara ekstensif. Yang ini bekerja untuk saya:

rsync -a ./FROM/ ./TO --exclude='.*'
Slatvick
sumber
1
Bukankah itu akan kehilangan file yang namanya dimulai dengan titik, seperti .htaccess?
Greg Hewgill
8
Solusi yang bagus, saya akan mengubah --exclude = '. *' Menjadi --exclude = '. Git *'
schmunk
18
--exclude-vcs jika Anda akan mengambil kebijaksanaan ini
plod
Bisakah ./FROM/ menjadi repo jarak jauh?
Resist Design
2
Sebagai FYI, salinan rsyncdaftar argumen saya sebagai --cvs-exclude. Selain itu, masih menyalin .gitattributesdan.gitignore
Ryan Ransford
19

Saya sering mengenai halaman ini ketika mencari cara untuk mengekspor repositori git. Jawaban saya untuk pertanyaan ini mempertimbangkan tiga properti yang svn ekspor telah desain dibandingkan dengan git, karena svn mengikuti pendekatan repositori terpusat:

  • Ini meminimalkan lalu lintas ke lokasi repositori jauh dengan tidak mengekspor semua revisi
  • Itu tidak termasuk informasi meta dalam direktori ekspor
  • Mengekspor cabang tertentu menggunakan svn dilakukan dengan menentukan jalur yang sesuai

    git clone --depth 1 --branch master git://git.somewhere destination_path
    rm -rf destination_path/.git
    

Saat membuat rilis tertentu, penting untuk mengkloning cabang stabil seperti misalnya --branch stableatau --branch release/0.9.

Lars Schillingmann
sumber
Ini tidak berfungsi jika tujuan ada dan tidak kosong.
Eponim
2
The One True Answer: muncul dari kedalaman. The git archive | tarpendekatan tidak dapat diterapkan untuk lingkungan shell POSIX-kompatibel (misalnya, AppVeyor ini CMD- atau CI berbasis PowerShell), yang merupakan non-ideal. The git checkoutPendekatan memodifikasi indeks dari pohon kerja utama, yang mengerikan. The git checkout-indexPendekatan membutuhkan indeks pohon kerja utama untuk dimodifikasi terlebih dahulu, yang bahkan mengerikan-er. git clonePendekatan tradisional mengkloning keseluruhan sejarah repositori sebelum menghapus sejarah itu, yang sia-sia. Ini adalah satu-satunya solusi waras yang tersisa.
Cecil Curry
1
Untuk mengekspor secara lokal, perhatikan bahwa jalur absolut dari pohon kerja Git yang akan dikloning harus diawali oleh file://protokol (misalnya, git clone --depth 1 --branch v3.14.15 file:///home/me/src_repo trg_repo). Gagal melakukannya akan memancarkan "warning: --depth is ignored in local clones; use file:// instead."dan melakukan standar daripada klon dangkal, mengalahkan seluruh tujuan jawaban ini. Salud!
Cecil Curry
16

Ini akan menyalin semua konten, minus file .dot. Saya menggunakan ini untuk mengekspor proyek klon git ke repo git aplikasi web saya tanpa barang .git.

cp -R ./path-to-git-repo / path / ke / tujuan /

Pesta tua polos bekerja sangat bagus :)

Harmon
sumber
Mengapa tidak mendorong saja ke remote? Bahkan lebih sederhana dari bash.
nurettin
2
bagaimana dengan file yang merupakan bagian dari aplikasi web dan namanya dimulai dengan titik? :) pikirkan tentang .htaccess
Artur
3
Terkadang Anda juga ingin mengabaikan apa yang ada di dalam .gitignore, ini tidak akan terjadi.
gratis
14

Sesederhana klon kemudian hapus folder .git:

git clone url_of_your_repo path_to_export && rm -rf path_to_export/.git

teleme.io
sumber
4
Jujur - jawaban ini, yang juga # 1 dalam pertanyaan - adalah apa yang akan Anda lakukan 99% dari waktu. Sebagian besar jawaban ini terlalu rumit.
Geoff Nixon
11

Untuk pengguna GitHub, git archive --remotemetode ini tidak akan berfungsi secara langsung, karena URL ekspor bersifat sementara . Anda harus meminta URL GitHub, lalu unduh URL itu. curlmembuatnya mudah:

curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | tar xzf -

Ini akan memberi Anda kode yang diekspor di direktori lokal. Contoh:

$ curl -L https://api.github.com/repos/jpic/bashworks/tarball | tar xzf -
$ ls jpic-bashworks-34f4441/
break  conf  docs  hack  LICENSE  mlog  module  mpd  mtests  os  README.rst  remote  todo  vcs  vps  wepcrack

Sunting
Jika Anda ingin kode dimasukkan ke direktori tertentu yang ada (bukan yang acak dari github):

curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | \
tar xzC /path/you/want --strip 1
uskup
sumber
11

Ya, ini adalah perintah yang bersih dan rapi untuk mengarsipkan kode Anda tanpa ada git yang dimasukkan dalam arsip dan baik untuk diedarkan tanpa khawatir tentang riwayat git commit.

git archive --format zip --output /full/path/to/zipfile.zip master 
zeeawan
sumber
Ini hebat, hanya perlu menghapus gitignore setelah dan selesai dan siap untuk dibagikan.
Sogger
Menghapus .gitgnore dll disebutkan dalam diterima komentar jawaban: penggunaan .gitattributes berkas, lihat feeding.cloud.geek.nz/posts/excluding-files-from-git-archive
Sogger
10

Saya hanya ingin menunjukkan bahwa dalam kasus Anda

  1. mengekspor sub folder repositori (itulah yang saya gunakan untuk menggunakan fitur ekspor SVN)
  2. tidak masalah dengan menyalin segala sesuatu dari folder itu ke tujuan penyebaran
  3. dan karena Anda sudah memiliki salinan seluruh repositori di tempatnya.

Maka Anda bisa menggunakan cp foo [destination]bukan yang disebutkan git-archive master foo | -x -C [destination].

dkinzer
sumber
9

Anda dapat mengarsipkan repo jarak jauh di komit apa pun sebagai file zip.

git archive --format=zip --output=archive.zip --remote=USERNAME@HOSTNAME:PROJECTNAME.git HASHOFGITCOMMIT
orkoden
sumber
8

Bash-implementasi git-ekspor.

Saya telah mensegmentasi proses pembuatan dan penghapusan file .empty pada fungsinya sendiri, dengan tujuan untuk menggunakannya kembali dalam implementasi 'git-archive' (akan diposting nanti).

Saya juga telah menambahkan file '.gitattributes' ke proses untuk menghapus file yang tidak diinginkan dari folder ekspor target. Termasuk verbosity ke proses sementara membuat fungsi 'git-ekspor' lebih efisien.

EMPTY_FILE = ". Empty";

function create_empty () {
## Processing path (target-dir):
    TRG_PATH="${1}";
## Component(s):
    EXCLUDE_DIR=".git";
echo -en "\nAdding '${EMPTY_FILE}' files to empty folder(s): ...";
    find ${TRG_PATH} -not -path "*/${EXCLUDE_DIR}/*" -type d -empty -exec touch {}/${EMPTY_FILE} \;
#echo "done.";
## Purging SRC/TRG_DIRs variable(s):
    unset TRG_PATH EMPTY_FILE EXCLUDE_DIR;
    return 0;
  }

declare -a GIT_EXCLUDE;
function load_exclude () {
    SRC_PATH="${1}";
    ITEMS=0; while read LINE; do
#      echo -e "Line [${ITEMS}]: '${LINE%%\ *}'";
      GIT_EXCLUDE[((ITEMS++))]=${LINE%%\ *};
    done < ${SRC_PATH}/.gitattributes;
    GIT_EXCLUDE[${ITEMS}]="${EMPTY_FILE}";
## Purging variable(s):
    unset SRC_PATH ITEMS;
    return 0;
  }

function purge_empty () {
## Processing path (Source/Target-dir):
    SRC_PATH="${1}";
    TRG_PATH="${2}";
echo -e "\nPurging Git-Specific component(s): ... ";
    find ${SRC_PATH} -type f -name ${EMPTY_FILE} -exec /bin/rm '{}' \;
    for xRULE in ${GIT_EXCLUDE[@]}; do
echo -en "    '${TRG_PATH}/{${xRULE}}' files ... ";
      find ${TRG_PATH} -type f -name "${xRULE}" -exec /bin/rm -rf '{}' \;
echo "done.'";
    done;
echo -e "done.\n"
## Purging SRC/TRG_PATHs variable(s):
    unset SRC_PATH; unset TRG_PATH;
    return 0;
  }

function git-export () {
    TRG_DIR="${1}"; SRC_DIR="${2}";
    if [ -z "${SRC_DIR}" ]; then SRC_DIR="${PWD}"; fi
    load_exclude "${SRC_DIR}";
## Dynamically added '.empty' files to the Git-Structure:
    create_empty "${SRC_DIR}";
    GIT_COMMIT="Including '${EMPTY_FILE}' files into Git-Index container."; #echo -e "\n${GIT_COMMIT}";
    git add .; git commit --quiet --all --verbose --message "${GIT_COMMIT}";
    if [ "${?}" -eq 0 ]; then echo " done."; fi
    /bin/rm -rf ${TRG_DIR} && mkdir -p "${TRG_DIR}";
echo -en "\nChecking-Out Index component(s): ... ";
    git checkout-index --prefix=${TRG_DIR}/ -q -f -a
## Reset: --mixed = reset HEAD and index:
    if [ "${?}" -eq 0 ]; then
echo "done."; echo -en "Resetting HEAD and Index: ... ";
        git reset --soft HEAD^;
        if [ "${?}" -eq 0 ]; then
echo "done.";
## Purging Git-specific components and '.empty' files from Target-Dir:
            purge_empty "${SRC_DIR}" "${TRG_DIR}"
          else echo "failed.";
        fi
## Archiving exported-content:
echo -en "Archiving Checked-Out component(s): ... ";
        if [ -f "${TRG_DIR}.tgz" ]; then /bin/rm ${TRG_DIR}.tgz; fi
        cd ${TRG_DIR} && tar -czf ${TRG_DIR}.tgz ./; cd ${SRC_DIR}
echo "done.";
## Listing *.tgz file attributes:
## Warning: Un-TAR this file to a specific directory:
        ls -al ${TRG_DIR}.tgz
      else echo "failed.";
    fi
## Purgin all references to Un-Staged File(s):
   git reset HEAD;
## Purging SRC/TRG_DIRs variable(s):
    unset SRC_DIR; unset TRG_DIR;
    echo "";
    return 0;
  }

Keluaran:

$ git-export /tmp/rel-1.0.0

Menambahkan file '.empty' ke folder kosong: ... selesai.

Komponen Indeks Memeriksa: ... selesai.

Menyetel ulang KEPALA dan Indeks: ... selesai.

Membersihkan komponen Khusus Git: ...

'/tmp/rel-1.0.0/{.buildpath}' file ... selesai. '

'/tmp/rel-1.0.0/{.project}' file ... selesai. '

'/tmp/rel-1.0.0/{.gitignore}' file ... selesai. '

'/tmp/rel-1.0.0/{.git}' file ... selesai. '

'/tmp/rel-1.0.0/{.gitattributes}' file ... selesai. '

'/tmp/rel-1.0.0/{*.mno}' file ... selesai. '

'/tmp/rel-1.0.0/{*~}' file ... selesai. '

'/tmp/rel-1.0.0/{.*~}' file ... selesai. '

'/tmp/rel-1.0.0/{*.swp}' file ... selesai. '

'/tmp/rel-1.0.0/{*.swo}' file ... selesai. '

'/tmp/rel-1.0.0/{.DS_Store}' file ... selesai. '

'/tmp/rel-1.0.0/{.settings}' file ... selesai. '

'/tmp/rel-1.0.0/{.empty}' file ... selesai. '

selesai

Komponen Pengarsipan Diperiksa: ... selesai.

-rw-r - r-- 1 admin roda 25445901 3 Nov 12:57 /tmp/rel-1.0.0.tgz

Saya sekarang telah memasukkan fungsionalitas 'arsip git' ke dalam satu proses yang memanfaatkan fungsi 'create_empty' dan fitur lainnya.

function git-archive () {
    PREFIX="${1}"; ## sudo mkdir -p ${PREFIX}
    REPO_PATH="`echo "${2}"|awk -F: '{print $1}'`";
    RELEASE="`echo "${2}"|awk -F: '{print $2}'`";
    USER_PATH="${PWD}";
echo "$PREFIX $REPO_PATH $RELEASE $USER_PATH";
## Dynamically added '.empty' files to the Git-Structure:
    cd "${REPO_PATH}"; populate_empty .; echo -en "\n";
#    git archive --prefix=git-1.4.0/ -o git-1.4.0.tar.gz v1.4.0
# e.g.: git-archive /var/www/htdocs /repos/domain.name/website:rel-1.0.0 --explode
    OUTPUT_FILE="${USER_PATH}/${RELEASE}.tar.gz";
    git archive --verbose --prefix=${PREFIX}/ -o ${OUTPUT_FILE} ${RELEASE}
    cd "${USER_PATH}";
    if [[ "${3}" =~ [--explode] ]]; then
      if [ -d "./${RELEASE}" ]; then /bin/rm -rf "./${RELEASE}"; fi
      mkdir -p ./${RELEASE}; tar -xzf "${OUTPUT_FILE}" -C ./${RELEASE}
    fi
## Purging SRC/TRG_DIRs variable(s):
    unset PREFIX REPO_PATH RELEASE USER_PATH OUTPUT_FILE;
    return 0;
  }
tocororo
sumber
Penggunaan: git-arsip [/ var / www / htdocs] /repos/web.domain/website:rel-1.0.0
tocororo
8

Jika Anda menginginkan sesuatu yang berfungsi dengan submodula, ini mungkin layak untuk dicoba.

catatan:

  • MASTER_DIR = checkout dengan kiriman Anda juga diperiksa
  • DEST_DIR = tempat ekspor ini akan berakhir
  • Jika Anda memiliki rsync, saya pikir Anda akan dapat melakukan hal yang sama dengan sakit bola yang bahkan lebih sedikit.

Asumsi:

  • Anda perlu menjalankan ini dari direktori induk MASTER_DIR (yaitu dari MASTER_DIR cd ..)
  • DEST_DIR diasumsikan telah dibuat. Ini cukup mudah dimodifikasi untuk memasukkan pembuatan DEST_DIR jika Anda mau

cd MASTER_DIR && tar -zcvf ../DEST_DIR/export.tar.gz --exclude = '. git *'. && cd ../DEST_DIR/ && tar xvfz export.tar.gz && rm export.tar.gz

Rob Jensen
sumber
6

Preferensi saya sebenarnya adalah memiliki dist target di Makefile Anda (atau sistem build lain) yang mengekspor arsip yang dapat didistribusikan kode Anda (.tar.bz2, .zip, .jar, atau apa pun yang sesuai). Jika Anda menggunakan autotools GNU atau sistem MakeMaker Perl, saya pikir ini ada untuk Anda secara otomatis. Jika tidak, saya sangat merekomendasikan untuk menambahkannya.

ETA (2012-09-06): Wow, downvotes yang keras. Saya masih percaya bahwa lebih baik untuk membangun distribusi Anda dengan alat membangun Anda daripada alat kontrol kode sumber Anda. Saya percaya dalam membangun artefak dengan alat membangun. Dalam pekerjaan saya saat ini, produk utama kami dibangun dengan target semut. Kami berada di tengah-tengah beralih sistem kontrol kode sumber, dan keberadaan target semut ini berarti satu kerumitan dalam migrasi.

skiphoppy
sumber
Proyek yang saya pikirkan bukanlah proyek kode; kebetulan lebih sejalan dengan proyek situs web.
Greg Hewgill
Tidak menjawab pertanyaan.
Andrew Ferrier
1
Ya, jawaban seperti itu mungkin tidak sesuai dengan kebutuhan semua orang, tetapi downvotesnya aneh. Ini adalah jawaban yang benar-benar valid, dan memang, dalam banyak skenario, satu-satunya jawaban yang benar. Itu membuat titik yang sangat valid bahwa memikirkan masalah ini sebagai "masalah alat vc" sering salah jalan sepenuhnya.
snogglethorpe
6

Ini akan menyalin file dalam rentang komit (C ke G) ke file tar. Catatan: ini hanya akan membuat file berkomitmen. Bukan seluruh repositori. Sedikit dimodifikasi dari sini

Contoh Sejarah Komit

A -> B -> C -> D -> E -> F -> G -> H -> I

git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT C~..G | xargs tar -rf myTarFile.tar

Halaman Manual git-diff-tree

-r -> recurse menjadi sub-tree

--no-commit-id -> git diff-tree menampilkan baris dengan ID komit jika berlaku. Bendera ini menekan output ID komit.

--nama-saja -> Tampilkan hanya nama file yang diubah.

--diff-filter = ACMRT -> Pilih hanya file-file ini. Lihat di sini untuk daftar lengkap file

C..G -> File dalam rentang komit ini

C ~ -> Sertakan file dari Komit C. Bukan hanya file sejak Komit C.

| xargs tar -rf myTarFile -> output ke tar

Kesemek Fuyu
sumber
5

Seperti yang saya pahami pertanyaannya, ini lebih tentang mengunduh keadaan tertentu dari server, tanpa riwayat, dan tanpa data cabang lain, daripada mengekstraksi keadaan dari repositori lokal (seperti yang dilakukan banyak penjawab di sini).

Itu bisa dilakukan seperti ini:

git clone -b someBranch --depth 1 --single-branch git://somewhere.com/repo.git \
&& rm -rf repo/.git/
  • --single-branch tersedia sejak Git 1.7.10 (April 2012).
  • --depthapakah (ternyata?) dilaporkan salah, tetapi untuk kasus ekspor, masalah yang disebutkan seharusnya tidak menjadi masalah.
Ondra Žižka
sumber
Catatan: Saya baru memperhatikan ada 2 halaman anwsers, saya hanya melihat satu sebelum memposting. Ada satu anwser serupa dengan hanya --depth, yang menyiratkan --single-branchkecuali --no-single-branchdiberikan, yang berarti ini mungkin memiliki efek yang sama. Namun tidak yakin, beberapa pakar mungkin mengonfirmasi?
Ondra Žižka
4

Saya membutuhkan ini untuk skrip penyebaran dan saya tidak bisa menggunakan salah satu pendekatan yang disebutkan di atas. Sebaliknya saya menemukan solusi yang berbeda:

#!/bin/sh
[ $# -eq 2 ] || echo "USAGE $0 REPOSITORY DESTINATION" && exit 1
REPOSITORY=$1
DESTINATION=$2
TMPNAME="/tmp/$(basename $REPOSITORY).$$"
git clone $REPOSITORY $TMPNAME
rm -rf $TMPNAME/.git
mkdir -p $DESTINATION
cp -r $TMPNAME/* $DESTINATION
rm -rf $TMPNAME
troelskn
sumber
Apa masalah dengan solusi read-tree / checkout-index atau arsip? Sejauh yang saya tahu Anda telah melakukan hal yang sama seperti mkdir -p "$2" && git --git-dir="$1" archive HEAD | tar -x -C "$2"tetapi agak panjang lebar.
CB Bailey
1
Saya tidak dapat mengaktifkan read-tree dari repositori jarak jauh, dan solusi arsip tidak berfungsi dengan github.
troelskn
Ya dengan arsip, dapatkan perintah Tidak Valid: 'git-unggah-arsip' ... kesalahan dan saya tidak punya opsi konfigurasi core.gitProxy dan set variabel lingkungan GIT_PROXY_COMMAND ditetapkan
tgkprog
4

Melakukannya dengan cara mudah, ini adalah fungsi untuk .bash_profile, secara langsung membuka ritsleting arsip di lokasi saat ini, konfigurasikan dulu [url: path] Anda yang biasa. CATATAN: Dengan fungsi ini Anda menghindari operasi klon, itu langsung dari repo jarak jauh.

gitss() {
    URL=[url:path]

    TMPFILE="`/bin/tempfile`"
    if [ "$1" = "" ]; then
        echo -e "Use: gitss repo [tree/commit]\n"
        return
    fi
    if [ "$2" = "" ]; then
        TREEISH="HEAD"
    else
        TREEISH="$2"
    fi
    echo "Getting $1/$TREEISH..."
    git archive --format=zip --remote=$URL/$1 $TREEISH > $TMPFILE && unzip $TMPFILE && echo -e "\nDone\n"
    rm $TMPFILE
}

Alias ​​untuk .gitconfig, konfigurasi yang sama diperlukan (TAKE CARE menjalankan perintah di dalam proyek .git, SELALU melompat ke dir basis sebelumnya seperti yang dikatakan di sini , sampai ini diperbaiki, saya pribadi lebih suka fungsi

ss = !env GIT_TMPFILE="`/bin/tempfile`" sh -c 'git archive --format=zip --remote=[url:path]/$1 $2 \ > $GIT_TMPFILE && unzip $GIT_TMPFILE && rm $GIT_TMPFILE' -
RkG
sumber
4

Saya punya solusi lain yang berfungsi dengan baik jika Anda memiliki salinan lokal repositori di mesin tempat Anda ingin membuat ekspor. Dalam hal ini, pindah ke direktori repositori ini, dan masukkan perintah ini:

GIT_WORK_TREE=outputdirectory git checkout -f

Ini sangat berguna jika Anda mengelola situs web dengan repositori git dan ingin checkout versi bersih di /var/www/. Dalam hal ini, tambahkan perintah ini dalam .git/hooks/post-receiveskrip ( hooks/post-receivepada repositori kosong, yang lebih cocok dalam situasi ini)

Tom
sumber
3

Saya pikir posting @Aredridel adalah yang terdekat, tetapi ada sedikit lebih dari itu - jadi saya akan menambahkan ini di sini; masalahnya adalah, di svn, jika Anda berada dalam subfolder dari repo, dan Anda melakukannya:

/media/disk/repo_svn/subdir$ svn export . /media/disk2/repo_svn_B/subdir

kemudian svnakan mengekspor semua file yang berada di bawah kendali revisi (mereka mungkin juga baru saja ditambahkan; atau status yang dimodifikasi) - dan jika Anda memiliki "sampah" lain di direktori itu (dan saya tidak menghitung .svnsubfolder di sini, tetapi hal-hal yang terlihat seperti .ofile) , itu tidak akan diekspor; hanya file-file yang terdaftar oleh repo SVN yang akan diekspor. Bagi saya, satu hal yang menyenangkan adalah bahwa ekspor ini juga menyertakan file dengan perubahan lokal yang belum dilakukan; dan satu lagi yang menyenangkan adalah bahwa cap waktu dari file yang diekspor sama dengan yang asli. Atau, seperti yang svn help exportdikatakan:

  1. Mengekspor pohon direktori bersih dari copy pekerjaan yang ditentukan oleh PATH1, pada revisi REV jika diberikan, jika tidak di BEKERJA, ke PATH2. ... Jika REV tidak ditentukan, semua perubahan lokal akan dipertahankan. File yang tidak di bawah kendali versi tidak akan disalin.

Untuk menyadari bahwa gittidak akan menyimpan stempel waktu, bandingkan output dari perintah-perintah ini (dalam subfolder dari gitrepo pilihan Anda):

/media/disk/git_svn/subdir$ ls -la .

... dan:

/media/disk/git_svn/subdir$ git archive --format=tar --prefix=junk/ HEAD | (tar -t -v --full-time -f -)

... dan saya, dalam hal apapun, pemberitahuan yang git archivemenyebabkan semua cap waktu dari file yang diarsipkan sama! git help archivemengatakan:

arsip git berperilaku berbeda ketika diberi ID pohon versus ketika diberikan ID komit atau ID tag. Dalam kasus pertama waktu saat ini digunakan sebagai waktu modifikasi setiap file dalam arsip. Dalam kasus terakhir, waktu komit yang dicatat dalam objek komit yang direferensikan digunakan sebagai gantinya.

... tetapi ternyata kedua kasus mengatur "waktu modifikasi setiap file"; dengan demikian tidak menjaga cap waktu yang sebenarnya dari file-file itu!

Jadi, untuk menjaga stempel waktu, berikut adalah bashskrip, yang sebenarnya adalah "satu-liner", meskipun agak rumit - jadi di bawah ini diposting dalam beberapa baris:

/media/disk/git_svn/subdir$ git archive --format=tar master | (tar tf -) | (\
  DEST="/media/diskC/tmp/subdirB"; \
  CWD="$PWD"; \
  while read line; do \
    DN=$(dirname "$line"); BN=$(basename "$line"); \
    SRD="$CWD"; TGD="$DEST"; \
    if [ "$DN" != "." ]; then \
      SRD="$SRD/$DN" ; TGD="$TGD/$DN" ; \
      if [ ! -d "$TGD" ] ; then \
        CMD="mkdir \"$TGD\"; touch -r \"$SRD\" \"$TGD\""; \
        echo "$CMD"; \
        eval "$CMD"; \
      fi; \
    fi; \
    CMD="cp -a \"$SRD/$BN\" \"$TGD/\""; \
    echo "$CMD"; \
    eval "$CMD"; \
    done \
)

Perhatikan bahwa diasumsikan bahwa Anda mengekspor konten dalam direktori "saat ini" (di atas, /media/disk/git_svn/subdir) - dan tujuan tujuan Anda mengekspornya agak tidak nyaman, tetapi berada dalam DESTvariabel lingkungan. Perhatikan bahwa dengan skrip ini; Anda harus membuat DESTdirektori sendiri secara manual, sebelum menjalankan skrip di atas.

Setelah skrip dijalankan, Anda harus dapat membandingkan:

ls -la /media/disk/git_svn/subdir
ls -la /media/diskC/tmp/subdirB   # DEST

... dan semoga melihat cap waktu yang sama (untuk file-file yang berada di bawah kontrol versi).

Semoga ini bisa membantu seseorang,
Ceria!

sdaau
sumber
3

git mengekspor ke arsip zip sambil menambahkan awalan (mis. nama direktori):

git archive master --prefix=directoryWithinZip/  --format=zip -o out.zip
DomTomCat
sumber
1

saya memiliki fungsi utilitas berikut dalam file .bashrc saya: ini membuat arsip cabang saat ini di repositori git.

function garchive()
{
  if [[ "x$1" == "x-h" || "x$1" == "x" ]]; then
    cat <<EOF
Usage: garchive <archive-name>
create zip archive of the current branch into <archive-name>
EOF
  else
    local oname=$1
    set -x
    local bname=$(git branch | grep -F "*" | sed -e 's#^*##')
    git archive --format zip --output ${oname} ${bname}
    set +x
  fi
}
MichaelMoser
sumber