GIT: wyewidencjonuj do określonego folderu

132

Chcę użyć czegoś podobnego do:

git checkout -- <path>/<file>

ale chcę wyrejestrować plik do wybranego przeze mnie folderu, zamiast nadpisywać lokalny <path>/<file>.

Dowolny pomysł?

Rafid
źródło
2
Zobacz: stackoverflow.com/questions/160608/…
Adam Vandenberg

Odpowiedzi:

58

Jak w Czy „eksport git” (np. „Eksport svn”)?

Możesz git checkout-indexdo tego użyć , jest to polecenie niskiego poziomu, jeśli chcesz wyeksportować wszystko, możesz użyć -a,

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

Aby zacytować strony podręcznika:

Końcowy znak „/” [na przedrostku] jest ważny. Wyeksportowana nazwa jest dosłownie po prostu poprzedzona określonym ciągiem.

Jeśli chcesz wyeksportować określony katalog, jest kilka sztuczek. Polecenie pobiera tylko pliki, a nie katalogi. Aby zastosować go do katalogów, użyj polecenia „find” i potokuj wyjście do git.

find dirname -print0 | git checkout-index --prefix=/path-to/dest/ -f -z --stdin

Również ze stron podręcznika:

Intuicyjność nie jest tutaj celem. Powtarzalność jest.

hasen
źródło
Niestety to nie zadziała z czystego repozytorium git, nawet z ustawieniem --prefix :-( (testowane z git 1.9.1)
apeiros
1
jeśli chcesz sprawdzić gałąź / zatwierdzenie czystego repozytorium git, użyjGIT_WORK_TREE=../path/to/place git checkout
allicoder
4
git worktree(patrz poniżej) imho jest dzisiaj kanoniczną odpowiedzią i można ją tutaj dodać.
geek-merlin
214

Kolejne rozwiązanie, które jest nieco czystsze - wystarczy określić inne drzewo robocze.

Aby sprawdzić wszystko, od HEAD (nie indeksu) do określonego katalogu wyjściowego:

git --work-tree=/path/to/outputdir checkout HEAD -- .

Aby pobrać podkatalog lub plik z HEAD do określonego katalogu:

git --work-tree=/path/to/outputdir checkout HEAD -- subdirname
Adrian Macneil
źródło
4
Drobna uwaga - potrzebujesz absolutnej ścieżki, ponieważ nie występuje rozwinięcie tyldy powłoki, tj. --work-tree=/home/thomasg/okcopyRaczej niż --work-tree=~/okcopy(prawdopodobnie użycie ścieżki względnej podczas siedzenia w tym samym drzewie git również działa, ale w ten sposób leży szaleństwo i git statuswyjścia w R'lyehian)
Tom Goodfellow
10
Działa zgodnie z oczekiwaniami również ze starymi zatwierdzeniami (np. Daje SHA zamiast HEAD), jednak git statuswtedy pokazuje wiele modów (prawdopodobnie dlatego, że indeks pasuje teraz do innego katalogu, a nie do nietkniętego normalnego drzewa roboczego). git resetprzywrócił go do dobrego stanu.
Tom Goodfellow
2
To samo tutaj git statuspokazuje wiele modów i git resetnie pomaga. Musiałem git checkout -f HEADprzywrócić stan mojego repozytorium.
DUzun
11
FYI: musisz samodzielnie utworzyć katalog, w przeciwnym razie fatal: This operation must be run in a work tree
pojawi
13
To katastrofalnie zmienia indeks głównego drzewa roboczego, który jest zazwyczaj zły. Jak sugeruje @TomGoodfellow, git resetwystarczy przywrócić główne drzewo robocze do zdrowia. Aby bezpiecznie eksportować podkatalogi repozytorium w dowolnym SHA1, gałęzi lub tagu bez modyfikowania głównego drzewa roboczego, zobacz niesławne rozwiązanie Charlesa Baileya . Podobnie, aby bezpiecznie płacić za wiele oddziałów w tym samym czasie, nowa podkomenda jest Twoim przyjacielem. git archivegit worktree add
Cecil Curry,
26

Dla pojedynczego pliku:

git show HEAD:abspath/to/file > file.copy
Tobu
źródło
2
+1 i wyjaśnienie „pewnego poprzedniego zatwierdzenia” (zamiast HEAD): Odnosi się do tego, SHA1 IDktóre można łatwo znaleźć poprzez gitk. Gdybym tylko potrzebował "wyewidencjonować" ten plik do tymczasowej lokalizacji (tj. Nie przywracać), showgit show 82e54378856215ef96c5db1ff1160a741b5dcd70:MyProj/proguard/mapping.txt > myproj_mapping.txt
użyłbym podkomendy
22

Jeśli pracujesz w ramach swojej funkcji i nie chcesz wracać do kasy, możesz uruchomić:

cd ./myrepo

git worktree add ../myrepo_master master

git worktree remove ../myrepo_master

Stworzy ../myrepo_masterkatalog z masterzatwierdzeniami gałęzi, w którym możesz kontynuować pracę

itsnikolay
źródło
1
Najlepsza odpowiedź - prosta iw przeciwieństwie do git --work-tree=/path/to/outputdir checkout HEAD -- .tego nie robi nic z indeksem, po prostu kopiuje wybraną gałąź do określonej lokalizacji (z dodatkiem pliku .git).
Roger Dueck,
Jak miałbym cofnąć tę zmianę?
Scott P.
@ ScottP.po prostu usuń myrepo_masterkatalog
itsnikolay
1
cofnięcie tego jest podkomendą z drzewa roboczego:git worktree remove ../myrepo_master
Martijn Dashorst
19

Powyższe rozwiązania nie zadziałały, ponieważ musiałem sprawdzić konkretną otagowaną wersję drzewa. Nawiasem cvs exportmówiąc , tak ma być używany. git checkout-indexnie przyjmuje argumentu znacznika, ponieważ pobiera pliki z indeksu. git checkout <tag>zmieniłby indeks niezależnie od drzewa roboczego, więc musiałbym zresetować oryginalne drzewo. Rozwiązaniem, które działało dla mnie, było sklonowanie repozytorium. Udostępniony klon jest dość szybki i nie zajmuje dużo dodatkowej przestrzeni. W .gitrazie potrzeby katalog można usunąć.

git clone --shared --no-checkout <repository> <destination>
cd <destination>
git checkout <tag>
rm -rf .git

Nowsze wersje git powinny obsługiwać git clone --branch <tag>automatyczne pobieranie określonego tagu:

git clone --shared --branch <tag> <repository> <destination>
rm -rf <destination>/.git
proski
źródło
3
git --work-tree=/path/to/outputdir checkout <tag> -- .nie działa dla Ciebie?
warvariuc
1
Nie, to nieprawda. Rzeczywisty plik w oryginalnym katalogu roboczym pozostaje niezmieniony, ale wersja pomostowa zostaje utracona i zastąpiona wersją z tagu. Jest to szczególnie złe, jeśli wersja etapowa zawiera starannie dobrany zestaw zmian do zatwierdzenia. Nie chcę, aby polecenie eksportu dotykało mojego indeksu, kropka.
proski
9

Odpowiedź Adriana brzmiała „fatalna: ta operacja musi być przeprowadzona w drzewie roboczym”. Oto, co zadziałało dla nas.

git worktree add <new-dir> --no-checkout --detach
cd <new-dir>
git checkout <some-ref> -- <existing-dir>

Uwagi:

  • --no-checkout Nie wypisuj niczego do nowego drzewa roboczego.
  • --detach Nie twórz nowej gałęzi dla nowego drzewa roboczego.
  • <some-ref>działa z każdym ref, na przykład, z którym działa HEAD~1.
  • Czyszczenie za pomocą git worktree prune.
Shaun Luttin
źródło
+1 za komentarze na temat tego, jak posprzątać - wszyscy są szczęśliwi mogąc narobić bałaganu w obecnym repozytorium. tylko ten nie ma skutków ubocznych.
Andrew Hill
1

Używam tego aliasu do wyewidencjonowywania gałęzi w katalogu tymczasowym:

[alias]
    cot = "!TEMP=$(mktemp -d); f() { git worktree prune && git worktree add $TEMP $1 && zsh -c \"cd $TEMP; zsh\";}; f" # checkout branch in temporary directory

Stosowanie:

git cot mybranch

Następnie zostaniesz przeniesiony do nowej powłoki w katalogu tymczasowym, w którym możesz pracować na gałęzi. Możesz nawet użyć poleceń git w tym katalogu.

Kiedy skończysz, usuń katalog i uruchom:

git worktree prune

Odbywa się to również automatycznie w aliasie, przed dodaniem nowego drzewa roboczego.

Felix Dietze
źródło
1

Dodatek do odpowiedzi @ hasen . Aby wyświetlić listę plików do pobrania , możesz użyć git ls-fileszamiast find:

git ls-files -z *.txt | git checkout-index --prefix=/path-to/dest/ -f -z --stdin
snipsnipsnip
źródło
Dziękujemy za prawidłowe użycie -z! Fajnie, że udostępniasz skrypt, który nie jest podatny na niektóre rodzaje ataków polegających na wstrzykiwaniu.
ErikE
0

Zdefiniowałem alias git, aby to osiągnąć (zanim znalazłem to pytanie).

Jest to krótka funkcja bash, która zapisuje bieżącą ścieżkę, przełącza się do repozytorium git, wykonuje wyewidencjonowanie i wraca tam, gdzie się zaczęła.

git checkto develop ~ / my_project_git

To np. Wyewidencjonowałoby gałąź deweloperską do katalogu "~ / my_project_git".

To jest kod aliasu w środku ~/.gitconfig:

[alias]
    checkTo = "!f(){ [ -z \"$1\" ] && echo \"Need to specify branch.\" && \
               exit 1; [ -z \"$2\" ] && echo \"Need to specify target\
               dir\" && exit 2; cDir=\"$(pwd)\"; cd \"$2\"; \
               git checkout \"$1\"; cd \"$cDir\"; };f"
cb0
źródło
0

Służy git archive branch-index | tar -x -C your-folder-on-PCdo klonowania gałęzi do innego folderu. Myślę, że wtedy możesz skopiować dowolny plik, którego potrzebujesz

dqthe
źródło