Czy „eksport git” (jak „eksport svn”)?

2356

Zastanawiałem się, czy istnieje dobre rozwiązanie „git export”, które tworzy kopię drzewa bez .gitkatalogu repozytorium. Znam co najmniej trzy metody:

  1. git clonea następnie usunięcie .gitkatalogu repozytorium.
  2. git checkout-index nawiązuje do tej funkcjonalności, ale zaczyna się od „Po prostu wczytaj wybrane drzewo do indeksu ...”, czego nie jestem do końca pewien, jak to zrobić.
  3. git-exportjest skryptem strony trzeciej, który zasadniczo wykonuje git clonetymczasową lokalizację rsync --exclude='.git'w miejscu docelowym.

Żadne z tych rozwiązań nie wydaje mi się satysfakcjonujące. Najbliższa svn exportmoże być opcja 1, ponieważ obie wymagają, aby katalog docelowy był najpierw pusty. Ale opcja 2 wydaje się jeszcze lepsza, zakładając, że mogę dowiedzieć się, co to znaczy wczytać drzewo do indeksu.

Greg Hewgill
źródło
1
@rnrTom: Zobacz odpowiedź Somowa. (w archiwum tar nie ma nic „skompresowanego”).
etarion
23
@mrTom git archive --format zip --output "output.zip" master -0da ci nieskompresowane archiwum (-0 to flaga dla nieskompresowanych). git-scm.com/docs/git-archive .
7
Zgadzam się z @mrTom i nie sądzę, czy głównym problemem jest to, czy archiwum jest skompresowane czy nieskompresowane. Za pomocą SVN mogę exportpodkatalog 250 kB bezpośrednio ze zdalnego repozytorium (który w innym przypadku mógłby mieć rozmiar 200 MB, z wyłączeniem poprawek) - i trafię do sieci tylko dla transferu pobierania 250 kB (lub więcej). Za pomocą git, archivemusi być włączony na serwerze (więc nie mogę go wypróbować) - clone --depth 1z serwera nadal można pobrać repo powiedzmy 25 MB, gdzie .gitsam podfolder zajmuje 15 MB. Dlatego nadal powiedziałbym, że odpowiedź brzmi „nie”.
sdaau
@ mrTom odpowiedź jest w rzeczywistości TAK Zobacz odpowiedź OP - polecenie brzmigit checkout-index
nocache
Oto ładny i prosty sposób:git archive -o latest.zip HEAD
Jewgienij Siergiejew

Odpowiedzi:

2396

Prawdopodobnie najprostszym sposobem na osiągnięcie tego jest git archive. Jeśli naprawdę potrzebujesz tylko rozwiniętego drzewa, możesz zrobić coś takiego.

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

Przez większość czasu muszę „eksportować” coś z git, w każdym razie chcę skompresowane archiwum, więc robię coś takiego.

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

Archiwum ZIP:

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

git help archive więcej szczegółów jest dość elastyczny.


Pamiętaj, że chociaż archiwum nie będzie zawierało katalogu .git, będzie ono jednak zawierać inne ukryte pliki specyficzne dla git, takie jak .gitignore, .gitattributes itp. Jeśli nie chcesz ich w archiwum, upewnij się, że użyj atrybutu export-ignore w pliku .gitattributes i zatwierdź to przed zrobieniem archiwum. Czytaj więcej...


Uwaga: Jeśli jesteś zainteresowany eksportem indeksu, polecenie to

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

(Więcej informacji znajduje się w odpowiedzi Grega )

CB Bailey
źródło
198
Archiwum ZIP:git archive --format zip --output /full/path master
Vadim
221
Pamiętaj, że archiwum nie będzie zawierało katalogu .git, ale będzie zawierać inne ukryte pliki specyficzne dla git, takie jak .gitignore, .gitattributes itp. Jeśli więc nie chcesz ich, upewnij się, że używasz atrybutu export-ignore w plik .gitattributes i zatwierdź go przed zrobieniem archiwum. Patrz feeding.cloud.geek.nz/2010/02/…
mj1531
54
Kontynuacja notatki dotyczącej strumieni: możesz dodać ciąg „--prefix = coś /” do polecenia, aby kontrolować nazwę katalogu, która będzie spakowana w pliku zip. Na przykład, jeśli użyjesz git archive --format zip --output /path/to/file.zip --prefix=newdir/ masterpliku wyjściowego, będzie on nazywał się „file.zip”, ale po rozpakowaniu katalog najwyższego poziomu będzie miał nazwę „newdir”. (Jeśli pominiesz atrybut --prefix, katalogiem najwyższego poziomu będzie „plik”.)
Alan W. Smith
89
Najprostszy sposób: git archive -o latest.zip HEADtworzy archiwum Zip, które zawiera zawartość ostatniego zatwierdzenia w bieżącym oddziale. Zauważ, że format wyjściowy wynika z rozszerzenia pliku wyjściowego.
nacho4d
37
Nie obsługuje podmodułów git :(
umpirsky
320

Dowiedziałem się, co oznacza opcja 2. Z repozytorium możesz:

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

Ukośnik na końcu ścieżki jest ważny, w przeciwnym razie spowoduje to, że pliki znajdą się w / destination z prefiksem „path”.

Ponieważ w normalnej sytuacji indeks zawiera zawartość repozytorium, nic specjalnego nie można zrobić, aby „wczytać żądane drzewo do indeksu”. Już tam jest

-aFlaga jest wymagane, aby sprawdzić wszystkie pliki w indeksie (nie jestem pewien, co to znaczy pominąć tę flagę w tej sytuacji, ponieważ nie robić to, co chcę). Te -fsiły flag zastępując wszystkie istniejące pliki w produkcji, które to polecenie normalnie nie robić.

To wydaje się być rodzajem „eksportu git”, którego szukałem.

Greg Hewgill
źródło
73
... i NIE ZAPOMNIJ CIĘCIA NA KOŃCU, inaczej nie uzyskasz pożądanego efektu;)
coni
1
git addPolecenie zmienia zawartość w indeksie, więc cokolwiek git statuspokazuje, jak „być popełnione” jest różnice pomiędzy głowicą i zawartości indeksu.
Greg Hewgill
7
@conny: przeczytaj swój komentarz, zapomniałem o nim i uruchomiłem polecenie bez końcowego ukośnika. wskazówka: postępuj zgodnie z radą
Coniaka
35
+1 do porady kumpla. Nie próbuj też tworzyć „~ / dest /”, ponieważ spowoduje to utworzenie katalogu o nazwie „~” w katalogu roboczym, a nie tego, co naprawdę chciałeś. Zgadnij, co się stanie, gdy bezmyślnie wpiszesz rm -rf ~
Kyle Heironimus
5
@KyleHeironimus - Twoje ostrzeżenie o używaniu '~ / dest /' jest prawdziwe, jeśli używasz cudzysłowów wokół ścieżki prefiksu, która mówi powłoce, aby nie wykonywała rozwijania tyldy. Katalog o nazwie ~(nie '~'!) Zostanie utworzony w twoim katalogu roboczym. Nie ma git checkout-indexw tym nic specjalnego : to samo dotyczy mkdir '~/dest'( nie rób tego! ). Kolejny dobry powód, aby unikać nazw plików, które wymagają cytowania (np. Które mają w nich spację) :-)
Matt Wallis
254

git archive działa również ze zdalnym repozytorium.

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

Aby wyeksportować określoną ścieżkę do repozytorium, dodaj tyle ścieżek, ile chcesz jako ostatni argument git, np .:

git archive --format=tar \
--remote=ssh://remote_server/remote_repository master path1/ path2/ | tar -xv
Alexander Somov
źródło
6
Ta opcja najbardziej mi się podoba. Ma tę dodatkową zaletę, że działa również na samych repozytoriach.
innaM
5
Poprawiona wersja to: git archive --format=tar --prefix=PROJECT_NAME/ --remote=USER@SERVER:PROJECT_NAME.git master | tar -xf - (upewnia się, że twoje archiwum znajduje się w folderze)
Nick
7
Uwaga : serwer musi włączyć tę funkcję.
Jakub Narębski,
12
Próbowałem: git archive --format=zip --output foo.zip --remote=https://github.com/xxx.git masterI zginęło: Operacja nie jest obsługiwana przez protokół. Nieoczekiwany koniec strumienia poleceń.
andyf
7
@and GitHub ma swoją własną drogę: curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | tar xzf -per docs
biskup
62

wprowadź opis zdjęcia tutaj

Specjalna odpowiedź na przypadek, jeśli repozytorium jest hostowane na GitHub.

Po prostu użyj svn export.

O ile wiem Github nie pozwala archive --remote. Chociaż GitHub jest kompatybilny z svn i mają wszystkie svndostępne repozytorium git, więc możesz używać go svn exporttak, jak zwykle, z kilkoma zmianami adresu URL GitHub.

Na przykład, aby wyeksportować całe repozytorium, zwróć uwagę, w jaki sposób trunkadres URL zastępuje master(lub dowolną inną gałąź HEAD projektu ):

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

Możesz wyeksportować pojedynczy plik lub nawet określoną ścieżkę lub folder:

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

Przykład z biblioteką JavaScript jQuery

HEADOddział lub mistrz oddział będzie dostępna za pomocą trunk:

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

Oddziały niebędące HEAD oddziałami będą dostępne pod /branches/:

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

Wszystkie tagi poniżej /tags/w ten sam sposób:

svn ls https://github.com/jquery/jquery/tags/2.1.3
Anthony Hatzopoulos
źródło
1
git archivewspółpracuje z GitHub, tak długo, jak używać protokołu git, po prostu wymienić https://się git://w adresie URL. Nie wiem, dlaczego GitHub nie reklamuje tej ukrytej funkcji.
Neil Mayhew
1
@NeilMayhew To nie działa dla mnie, rozumiem fatal: The remote end hung up unexpectedly. Wypróbowałem na dwóch różnych serwerach z repozytorium jQuery github.
Anthony Hatzopoulos
Masz rację. Zapomniałem, że używam git config url.<base>.insteadOfdo buforowania zdalnego repozytorium. Dlatego file://w rzeczywistości używałem adresu URL. Wątpię, aby git archivekiedykolwiek działał z git://adresami URL, ponieważ musi być w stanie działać git-upload-archivena zdalnym końcu. Powinno to być możliwe przy użyciu sshprotokołu, z wyjątkiem tego, że github nie pozwala na to ( Invalid command: 'git-upload-archive').
Neil Mayhew
W jaki sposób można użyć narzędzia lokalnego serwera zachowującego się jak github, jeśli chcę to zrobić na wewnętrznie hostowanych repozytoriach git?
kriss
1
upvoted - to całkowicie dziwne, że Git nie ma tej funkcji i musimy uciekać się do svn
Jason S
40

Z podręcznika Git :

Użycie git-checkout-index do „wyeksportowania całego drzewa”

Możliwość prefiksu sprawia, że ​​trywialne jest użycie indeksu git-checkout jako funkcji „eksportuj jako drzewo”. Po prostu przeczytaj wybrane drzewo do indeksu i wykonaj:

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

jperras
źródło
19
Myślę, że zamieszanie dotyczy frazy „wczytaj wybrane drzewo do indeksu”.
davetron5000
4
Jeśli chcesz wyeksportować katalog foo na pasku gałęzi, to będzie to git read-tree bar:fooA potem git checkout-index --prefix=export_dir/ -amoże powinieneś zrobićgit update-index master
Pascal Rosin
1
@JohnWeldon Czy wymaga to najpierw sklonowania repozytorium? Jeśli tak, to nie zaakceptowałbym tego, ponieważ cały punkt „eksportu svn” podkatalogu polega na bezpośrednim uzyskaniu kopii tego podkatalogu; jeśli ktoś ma repozytorium Git 1 GB i wszystko, czego chcę, to podkatalog 10kB, szaleństwo wymaga ode mnie sklonowania całej rzeczy.
Jason S
3
Również echo @ davetron5000 z komentarzem „przeczytaj żądane drzewo do indeksu”, co nie mam pojęcia, co to znaczy.
Jason S
38

Napisałem proste opakowanie git-checkout-index, którego możesz użyć w następujący sposób:

git export ~/the/destination/dir

Jeśli katalog docelowy już istnieje, musisz dodać -flub --force.

Instalacja jest prosta; po prostu upuść skrypt gdzieś w swoim wnętrzu PATHi upewnij się, że jest wykonywalny.

Repozytorium github dla git-export

Daniel Schierbeck
źródło
15
To opakowanie nie jest zależne od platformy; opiera się na / bin / sh. Więc jeśli korzystasz z systemu Windows, to rozwiązanie prawdopodobnie nie będzie dla ciebie działać.
shovavnik
18
Ten skrypt zawiera 57 wierszy dokumentacji, białych znaków, ustawień, analizy argumentów i tylko jedną linię, która faktycznie coś robi ...
Vladimir Panteleev
36

Wygląda na to, że jest to mniejszy problem z Git niż SVN. Git umieszcza tylko folder .git w katalogu głównym repozytorium, podczas gdy SVN umieszcza folder .svn w każdym podkatalogu. Tak więc „svn export” unika rekurencyjnej magii wiersza poleceń, podczas gdy w Git rekurencja nie jest konieczna.

kostmo
źródło
26
Począwszy od wersji SVN 1.7 istnieje tylko jeden folder .svn: subversion.apache.org/docs/release-notes/1.7.html#single-db
kostmo
Nie pozbędzie się to żadnych dodatkowych plików kompilacji, które svn usuwa z eksportu. To zdecydowanie nie jest odpowiedź.
ygoe
28

Odpowiednik

svn export . otherpath

wewnątrz istniejącego repozytorium jest

git archive branchname | (cd otherpath; tar x)

Odpowiednik

svn export url otherpath

jest

git archive --remote=url branchname | (cd otherpath; tar x)
aredridel
źródło
1
dzięki, tego mi brakowało ... również, aby sprawdzić znaczniki czasu eksportu (nie zostaną zachowane jak w plikach), użyj git archive --format=tar --prefix=junk/ HEAD | (tar -t -v --full-time -f -)... Jednak archiwizacja za pomocą znaczników czasu nie jest trywialna, więc opublikowałem przykład poniżej .
sdaau
1
Możesz użyć opcji C dla tar zamiast podpowłoki, w ten sposób: git archive branchname | tar xC otherpath
James Moore,
Heads up, że Copcja tar to tylko GNU Tar.
aredridel
22

Jeśli nie wykluczasz plików, .gitattributes export-ignorespróbujgit checkout

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

-f
Podczas sprawdzania ścieżek z indeksu nie zawieść przy nie połączonych wpisach; zamiast tego nie scalone wpisy są ignorowane.

i

-q
Unikaj gadatliwości

Dodatkowo możesz uzyskać dowolny oddział lub tag lub z konkretnej rewizji zatwierdzenia, jak w SVN, po prostu dodając SHA1 (SHA1 w Git jest równoważny z numerem rewizji w SVN)

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

/path/to/checkout/Musi być pusty, Git nie usunie dowolny plik, ale nadpisuje pliki o tej samej nazwie, bez żadnego ostrzeżenia

AKTUALIZACJA: Aby uniknąć problemu z ścięciem głowy lub pozostawienia nienaruszonego działającego repozytorium podczas korzystania z kasy do eksportu z tagami, gałęziami lub SHA1, należy dodać -- ./na końcu

Podwójny myślnik --mówi gitowi, że wszystko po myślnikach to ścieżki lub pliki, a także w tym przypadku mówi, git checkoutaby nie zmieniaćHEAD

Przykłady:

To polecenie pobierze tylko katalog libs, a także readme.txtplik z tego właśnie zatwierdzenia

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

Spowoduje to utworzenie (nadpisanie) my_file_2_behind_HEAD.txtdwóch zatwierdzeń za głowąHEAD^2

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

Aby uzyskać eksport innego oddziału

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

Zauważ, że ./jest względny względem katalogu głównego repozytorium

5286776117878
źródło
Właściwie, wśród wielu innych i pozytywnych opinii, to działało najlepiej dla mnie, bez żadnych kompresji, działając dobrze z nagimi repozytoriami (gitolite).
zabiera
1
Zauważ, że kasa SHA1 stworzy problem „ścięcia głowy” w repozytorium
user5286776117878
w rzeczywistości @ITGabs, to nie pobiera folderu „.git”.
Pobrany
@FabioMarreco Problem ściąga dotyczy repozytorium, którego nie ma w eksportowanych / pobieranych plikach, aktualizuję odpowiedź, aby uzyskać więcej informacji
użytkownik5286776117878
3
To zadziałało dla mnie świetnie. Ale na początku otrzymałem komunikat o błędzie „Nie repozytorium git”. Potem odkryłem, że „/ path / to / repo /” musi wskazywać na folder .git. Więc zadziałało: --git-dir = / path / to / repo / .git
philburk
21

Używam git-submodules intensywnie. Ten działa dla mnie:

rsync -a ./FROM/ ./TO --exclude='.*'
slatvick
źródło
1
Czy nie pominie plików, których nazwy zaczynają się od kropki, takich jak .htaccess?
Greg Hewgill,
8
Dobre rozwiązanie, chciałbym zmienić --exclude = '. *' Na --exclude = '. Git *'
schmunk
18
--Exclude-vcs, jeśli zamierzasz skorzystać z tego taktu
plod
Czy ./FROM/ może być zdalnym repozytorium?
Resist Design
2
Jako FYI, moja kopia rsynclisty wymienia argument jako --cvs-exclude. Ponadto nadal kopiuje .gitattributesi.gitignore
Ryan Ransford
19

Często odwiedzam tę stronę, gdy szukam sposobu na wyeksportowanie repozytorium git. Moja odpowiedź na to pytanie dotyczy trzech właściwości, które eksport svn ma z założenia w porównaniu z git, ponieważ svn działa zgodnie ze scentralizowanym repozytorium:

  • Minimalizuje ruch do zdalnej lokalizacji repozytorium, nie eksportując wszystkich wersji
  • Nie zawiera meta informacji w katalogu eksportu
  • Eksport określonej gałęzi za pomocą svn odbywa się poprzez określenie odpowiedniej ścieżki

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

Podczas budowania określonego wydania przydatne jest sklonowanie stabilnej gałęzi, na przykład --branch stablelub --branch release/0.9.

Lars Schillingmann
źródło
To nie działa, jeśli miejsce docelowe istnieje i nie jest puste.
Tytułowy
2
Jedna prawdziwa odpowiedź: wynika z głębin. git archive | tarPodejście zastosowania POSIX niekompatybilnych środowisku powłoki (np AppVeyor w CMD- lub CI PowerShell oparciu), który jest nie-idealne. git checkoutPodejście modyfikuje indeks głównej gałęzi roboczej, co jest okropne. git checkout-indexPodejście wymaga indeksu głównego drzewa roboczego zostać zmodyfikowany wcześniej, co jest nawet straszne-er. Tradycyjne git clonepodejście klonuje całą historię repozytorium przed usunięciem tej historii, co jest marnotrawstwem. To jedyne rozsądne rozwiązanie.
Cecil Curry,
1
Aby eksportować lokalnie, zwróć uwagę, że bezwzględna ścieżka drzewa roboczego Git, z którego ma zostać sklonowane, powinna być poprzedzona file://protokołem (np git clone --depth 1 --branch v3.14.15 file:///home/me/src_repo trg_repo.). Niezastosowanie się do tego spowoduje wyemitowanie "warning: --depth is ignored in local clones; use file:// instead."i wykonanie standardowego, a nie płytkiego klonu, co zniweczy cały cel tej odpowiedzi. Salud!
Cecil Curry,
16

Spowoduje to skopiowanie całej zawartości minus pliki .dot. Używam tego do eksportowania sklonowanych projektów git do repozytorium git mojej aplikacji internetowej bez plików .git.

cp -R ./path-to-git-repo / path / to / destination /

Zwykły stary bash działa po prostu świetnie :)

Harmon
źródło
Dlaczego nie po prostu naciskać na pilota? Jeszcze prostsze niż bash.
nurettin
2
co z plikami, które są częścią aplikacji internetowych, a ich nazwa zaczyna się od kropki? :) pomyśl o .htaccess
Artur
3
Czasami chcesz też zignorować to, co jest w środku .gitignore, to nie będzie.
fregante
14

Tak proste jak klon, a następnie usuń folder .git:

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

teleme.io
źródło
4
Szczerze mówiąc - ta odpowiedź, która jest również nr 1 w pytaniu - jest tym, co będziesz robić w 99% przypadków. Większość z tych odpowiedzi jest szalenie skomplikowana.
Geoff Nixon,
11

W przypadku użytkowników GitHub git archive --remotemetoda nie będzie działać bezpośrednio, ponieważ eksportowany adres URL jest efemeryczny . Musisz poprosić GitHub o adres URL, a następnie pobrać ten adres URL. curlułatwia to:

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

To da ci wyeksportowany kod z lokalnego katalogu. Przykład:

$ 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

Edytuj
Jeśli chcesz umieścić kod w określonym, istniejącym katalogu (zamiast losowego z github):

curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | \
tar xzC /path/you/want --strip 1
biskup
źródło
11

Tak, to jest czysty i schludny polecenia do archiwizowania kodu bez włączenia git w archiwum i jest dobry, aby przejść wokół bez obaw o jakiekolwiek git commit historię.

git archive --format zip --output /full/path/to/zipfile.zip master 
zeeawan
źródło
To jest świetne, wystarczy usunąć gitignore po i jest gotowe i gotowe do udostępnienia.
Sogger
Usuwanie plików .gitgnore itp. Jest wspomniane w zaakceptowanych komentarzach: użyj pliku .gitattributes, patrz feeding.cloud.geek.nz/posts/exclusion-files-from-git-archive
Sogger
10

Chcę tylko podkreślić, że w przypadku, gdy jesteście

  1. eksportowanie podfolderu repozytorium (tak korzystałem z funkcji eksportu SVN)
  2. są w porządku, kopiując wszystko z tego folderu do miejsca docelowego wdrażania
  3. a ponieważ masz już kopię całego repozytorium na swoim miejscu.

Następnie możesz po prostu użyć cp foo [destination]zamiast wspomnianego git-archive master foo | -x -C [destination].

dkinzer
źródło
9

Możesz zarchiwizować zdalne repo przy dowolnym zatwierdzeniu jako plik zip.

git archive --format=zip --output=archive.zip --remote=USERNAME@HOSTNAME:PROJECTNAME.git HASHOFGITCOMMIT
orkoden
źródło
8

Bash-wdrożenie git-export.

Procesy tworzenia i usuwania plików .segmentowałem według własnych funkcji, aby ponownie wykorzystać je w implementacji „git-archive” (zostaną opublikowane później).

Dodałem również do procesu plik „.gitattributes”, aby usunąć niepotrzebne pliki z docelowego folderu eksportu. Uwzględniono szczegółowość procesu, jednocześnie zwiększając wydajność funkcji „git-export”.

EMPTY_FILE = ". Pusty";

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;
  }

Wynik:

$ git-export /tmp/rel-1.0.0

Dodawanie „pustych” plików do pustych folderów: ... gotowe.

Składniki indeksu wymeldowania: ... gotowe.

Resetowanie HEAD i indeksu: ... gotowe.

Usuwanie składników specyficznych dla Gita: ...

„/tmp/rel-1.0.0/{.buildpath}„ pliki ... gotowe. ”

Pliki „/tmp/rel-1.0.0/{.project}”… gotowe. ”

„/tmp/rel-1.0.0/{.gitignore}„ pliki ... gotowe. ”

Pliki „/tmp/rel-1.0.0/{.git}”… gotowe. ”

„/tmp/rel-1.0.0/{.gitattributes}„ pliki ... gotowe. ”

Pliki „/tmp/rel-1.0.0/{*.mno}”… gotowe. ”

Pliki „/tmp/rel-1.0.0/{*~}”… gotowe. ”

Pliki „/tmp/rel-1.0.0/{.*~}”… gotowe. ”

Pliki „/tmp/rel-1.0.0/{*.swp}”… gotowe. ”

Pliki „/tmp/rel-1.0.0/{*.swo}”… gotowe. ”

Pliki „/tmp/rel-1.0.0/{.DS_Store}„ gotowe ... ”.

Pliki „/tmp/rel-1.0.0/{.settings}”… gotowe. ”

Pliki „/tmp/rel-1.0.0/{.empty}”… gotowe. ”

gotowy.

Archiwizacja wyewidencjonowanych komponentów: ... zrobione.

-rw-r - r-- 1 koło administracyjne 25445901 3 listopada 12:57 /tmp/rel-1.0.0.tgz

Włączyłem teraz funkcję „git archive” do jednego procesu, który korzysta z funkcji „create_empty” i innych funkcji.

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;
  }
minutę
źródło
Zastosowanie: git-archive [/ var / www / htdocs] /repos/web.domain/website:rel-1.0.0
tocororo
8

Jeśli chcesz czegoś, co działa z podmodułami, warto spróbować.

Uwaga:

  • MASTER_DIR = kasa z wymeldowanymi modułami również
  • DEST_DIR = gdzie skończy się ten eksport
  • Jeśli masz rsync, myślę, że byłbyś w stanie zrobić to samo z jeszcze mniejszym bólem piłki.

Założenia:

  • Musisz uruchomić to z katalogu nadrzędnego MASTER_DIR (tj. Z MASTER_DIR cd ..)
  • Zakłada się, że DEST_DIR został utworzony. Jest to dość łatwe do zmodyfikowania, aby uwzględnić utworzenie DEST_DIR, jeśli chcesz

cd KATALOG_GŁÓWNY && tar -zcvf ../DEST_DIR/export.tar.gz --exclude = '. git *'. && cd ../DEST_DIR/ && tar xvfz export.tar.gz && rm export.tar.gz

Rob Jensen
źródło
6

W rzeczywistości wolałbym mieć cel dist w twoim Makefile (lub innym systemie kompilacji), który eksportuje dystrybuowalne archiwum twojego kodu (.tar.bz2, .zip, .jar lub cokolwiek innego, co jest odpowiednie). Jeśli akurat używasz GNU autotools lub systemów MakeMaker Perla, myślę, że istnieje ono automatycznie. Jeśli nie, zdecydowanie polecam dodanie tego.

ETA (2012-09-06): Wow, surowe opinie. Nadal uważam, że lepiej jest budować swoje dystrybucje za pomocą narzędzi do budowania niż narzędzia do kontroli kodu źródłowego. Wierzę w budowanie artefaktów za pomocą narzędzi do budowania. W mojej obecnej pracy nasz główny produkt jest zbudowany z celem mrówek. Jesteśmy w trakcie przełączania systemów kontroli kodu źródłowego, a obecność tego celu mrówek oznacza o jeden problem z migracją.

skiphoppy
źródło
Projekt, który miałem na myśli, nie jest projektem kodowym; zdarza się, że jest to bardziej zgodne z projektem witryny internetowej.
Greg Hewgill
Nie odnosi się do pytania.
Andrew Ferrier,
1
Tak, taka odpowiedź może nie odpowiadać potrzebom wszystkich, ale opinie negatywne są dziwaczne. Jest to całkowicie poprawna odpowiedź i rzeczywiście, w wielu scenariuszach, jedyna poprawna odpowiedź. Wskazuje to bardzo słusznie, że myślenie o tym problemie jako o „problemie z narzędziem VC” często idzie całkowicie w złym kierunku.
snogglethorpe
6

Spowoduje to skopiowanie plików z zakresu zatwierdzeń (C do G) do pliku tar. Uwaga: spowoduje to tylko zatwierdzenie plików. Nie całe repozytorium. Lekko zmodyfikowany tutaj

Przykładowa historia zatwierdzeń

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

git-diff-tree Podręcznik strony

-r -> recurse w sub-drzewa

--no-commit-id -> git diff-tree wyświetla linię z identyfikatorem zatwierdzenia, jeśli dotyczy. Ta flaga pomija wyjściowy identyfikator zatwierdzenia.

- tylko nazwa -> Pokaż tylko nazwy zmienionych plików.

--diff-filter = ACMRT -> Wybierz tylko te pliki. Zobacz tutaj pełną listę plików

C..G -> Pliki w tym zakresie zatwierdzeń

C ~ -> Dołącz pliki z Commit C. Nie tylko pliki od Commit C.

| xargs tar -rf myTarFile -> wyjścia do tar

Fuyu Persimmon
źródło
5

Jak rozumiem pytanie, chodzi bardziej o pobieranie określonego stanu z serwera, bez historii i bez danych innych gałęzi, zamiast wyodrębniania stanu z lokalnego repozytorium (jak robi to wielu anwsers).

Można to zrobić w następujący sposób:

git clone -b someBranch --depth 1 --single-branch git://somewhere.com/repo.git \
&& rm -rf repo/.git/
  • --single-branch jest dostępna od wersji Git 1.7.10 (kwiecień 2012 r.).
  • --depthjest (był?) podobno wadliwy, ale w przypadku eksportu wspomniane problemy nie powinny mieć znaczenia.
Ondra Žižka
źródło
Uwaga: Właśnie zauważyłem, że są 2 strony anwsers, obejrzałem tylko jedną przed opublikowaniem. Istnieje tylko jedna podobna odpowiedź --depth, co oznacza, --single-branchże jeśli nie --no-single-branchzostanie podana, co oznacza, że ​​prawdopodobnie ma to ten sam efekt. Nie jesteś pewien, czy jakiś ekspert może to potwierdzić?
Ondra Žižka
4

Potrzebowałem tego do skryptu wdrażania i nie mogłem zastosować żadnego z wyżej wymienionych podejść. Zamiast tego wymyśliłem inne rozwiązanie:

#!/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
źródło
Na czym polegał problem z drzewem odczytu / indeksem kasy lub rozwiązaniem archiwalnym? O ile mogę stwierdzić, że zrobiłeś odpowiednik czegoś takiego, mkdir -p "$2" && git --git-dir="$1" archive HEAD | tar -x -C "$2"ale nieco dłużej nakręcony.
CB Bailey,
1
Nie mogłem zmusić drzewa odczytu do pracy ze zdalnego repozytorium, a rozwiązanie do archiwizacji nie działa z github.
troelskn
Tak, z archiwum pobierz niepoprawne polecenie: „git-upload-archive” ... błąd i nie mam opcji konfiguracji core.gitProxy oraz zestawu zmiennych środowiskowych
GIT_PROXY_COMMAND
4

Robiąc to w prosty sposób, jest to funkcja dla .bash_profile, bezpośrednio rozpakowuje archiwum na bieżącą lokalizację, najpierw skonfiguruj swój zwykły [url: path]. UWAGA: Dzięki tej funkcji unikasz operacji klonowania, pobierana jest ona bezpośrednio ze zdalnego repozytorium.

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 ​​dla .gitconfig, wymagana taka sama konfiguracja (ZADBAJ o wykonanie polecenia w projektach .git, ZAWSZE przeskakuje do katalogu podstawowego, jak tu powiedziano , dopóki nie zostanie to naprawione Osobiście wolę funkcję

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
źródło
4

Zdecydowanie najłatwiejszym sposobem, w jaki to zrobiłem (i działa również w systemie Windows) jest git bundle:

git bundle create /some/bundle/path.bundle --all

Zobacz tę odpowiedź, aby uzyskać więcej informacji: Jak mogę skopiować moje repozytorium git z mojego komputera z systemem Windows na komputer z systemem Linux za pomocą napędu USB?

BT
źródło
git bundlezawiera .gitfolder, czego nie chce OP; git archivewydaje się bardziej odpowiedni sposób
ssc
Gdzie jest dokumentacja na --allprzełączniku?
Garret Wilson,
4

Mam inne rozwiązanie, które działa dobrze, jeśli masz lokalną kopię repozytorium na komputerze, na którym chcesz utworzyć eksport. W takim przypadku przejdź do tego katalogu repozytorium i wprowadź następującą komendę:

GIT_WORK_TREE=outputdirectory git checkout -f

Jest to szczególnie przydatne, jeśli zarządzasz witryną z repozytorium git i chciałbyś pobrać czystą wersję /var/www/. W takim przypadku dodaj tę komendę do .git/hooks/post-receiveskryptu ( hooks/post-receivew nagim repozytorium, co jest bardziej odpowiednie w tej sytuacji)

Tomek
źródło
3

Myślę, że post @Aredridel był najbliższy, ale jest w tym coś więcej - dodam to tutaj; chodzi o to, svnże jeśli jesteś w podfolderze repozytorium i robisz:

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

następnie svnwyeksportuje wszystkie pliki, które są pod kontrolą wersji (mogły mieć również świeżo dodany lub status Zmodyfikowany) - a jeśli masz inne „śmieci” w tym katalogu (i nie liczę .svntutaj podfolderów, ale widoczne rzeczy takie jak .opliki) , nie będzie eksportowany; tylko pliki zarejestrowane przez repozytorium SVN zostaną wyeksportowane. Dla mnie jedną fajną rzeczą jest to, że ten eksport obejmuje również pliki z lokalnymi zmianami, które nie zostały jeszcze zatwierdzone; a kolejną fajną rzeczą jest to, że znaczniki czasu eksportowanych plików są takie same jak oryginalne. Lub, jak svn help exportto ujmuje:

  1. Eksportuje czyste drzewo katalogów z kopii roboczej określonej przez PATH1, w wersji REV, jeśli jest ono podane, w przeciwnym razie podczas WORKING, do PATH2. ... Jeśli nie określono REV, wszystkie lokalne zmiany zostaną zachowane. Pliki niepodlegające kontroli wersji nie zostaną skopiowane.

Aby zdać sobie sprawę, że gitnie zachowa znaczników czasu, porównaj dane wyjściowe tych poleceń (w podfolderze wybranego gitrepozytorium):

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

... i:

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

... a ja w każdym razie zauważam, że git archivepowoduje to, że wszystkie znaczniki czasu zarchiwizowanego pliku są takie same! git help archivemówi:

Archiwum git zachowuje się inaczej, gdy otrzyma identyfikator drzewa, niż gdy otrzyma identyfikator zatwierdzenia lub identyfikator znacznika. W pierwszym przypadku aktualny czas jest używany jako czas modyfikacji każdego pliku w archiwum. W tym ostatnim przypadku używany jest czas zatwierdzenia zapisany w przywoływanym obiekcie zatwierdzenia.

... ale najwyraźniej oba przypadki ustawiają „czas modyfikacji każdego pliku”; tym samym nie zachowując rzeczywistych znaczników czasu tych plików!

Tak więc, aby zachować także znaczniki czasu, oto bashskrypt, który w rzeczywistości jest „jednowierszowy”, choć nieco skomplikowany - więc poniżej jest opublikowany w wielu wierszach:

/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 \
)

Zauważ, że zakłada się, że eksportujesz zawartość do „bieżącego” katalogu (powyżej /media/disk/git_svn/subdir) - a miejsce docelowe, do którego eksportujesz, jest nieco niedogodnie umieszczone, ale znajduje się w DESTzmiennej środowiskowej. Zauważ, że z tym skryptem; musisz utworzyć DESTkatalog ręcznie, przed uruchomieniem powyższego skryptu.

Po uruchomieniu skryptu powinieneś być w stanie porównać:

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

... i mam nadzieję, że zobaczą te same znaczniki czasu (dla plików, które były pod kontrolą wersji).

Mam nadzieję, że to komuś pomoże,
zdrowie!

sdaau
źródło
3

eksport gita do archiwum zip podczas dodawania prefiksu (np. nazwa katalogu):

git archive master --prefix=directoryWithinZip/  --format=zip -o out.zip
DomTomCat
źródło
1

Mam następującą funkcję narzędzia w moim pliku .bashrc: tworzy archiwum bieżącego oddziału w repozytorium 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
źródło