GIT: Checkout para uma pasta específica

128

Eu quero usar algo semelhante a:

git checkout -- <path>/<file>

mas quero fazer check-out do arquivo para alguma pasta que eu escolher, em vez de substituir o local <path>/<file>.

Qualquer ideia?

Rafid
fonte
2
Veja: stackoverflow.com/questions/160608/…
Adam Vandenberg

Respostas:

57

Conforme faz uma "exportação de git" (como "exportação de svn")?

Você pode usar git checkout-indexpara isso, este é um comando de baixo nível. Se você deseja exportar tudo, pode usar -a,

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

Para citar as páginas de manual:

O final "/" [no prefixo] é importante. O nome exportado é literalmente apenas prefixado com a sequência especificada.

Se você deseja exportar um determinado diretório, existem alguns truques envolvidos. O comando leva apenas arquivos, não diretórios. Para aplicá-lo aos diretórios, use o comando 'find' e direcione a saída para o git.

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

Também nas páginas do manual:

Intuição não é o objetivo aqui. Repetibilidade é.

hasen
fonte
Infelizmente isso não vai funcionar a partir de um repositório git nua, mesmo com o conjunto --prefix :-( (testado com o Git 1.9.1)
apeiros
1
se você quiser conferir uma filial / confirmação de um repositório git bare, usoGIT_WORK_TREE=../path/to/place git checkout
allicoder
4
git worktree(veja abaixo) imho é a resposta canônica hoje e pode ser adicionada aqui.
Geek-merlin
213

Outra solução um pouco mais limpa - basta especificar uma árvore de trabalho diferente.

Para fazer o checkout de tudo, do HEAD (não do índice) para um diretório de saída específico:

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

Para fazer check-out de um subdiretório ou arquivo do HEAD para um diretório específico:

git --work-tree=/path/to/outputdir checkout HEAD -- subdirname
Adrian Macneil
fonte
4
Nota menor - você precisa de um caminho absoluto como shell til expansão não ocorre, ou seja, --work-tree=/home/thomasg/okcopyem vez de --work-tree=~/okcopy(possivelmente usando um caminho relativo ao sentar-se no interior da mesma árvore git funciona também, mas dessa forma mentiras loucura e git statussaídas em R'lyehian)
Tom Goodfellow
10
Também funciona como esperado com confirmações antigas (por exemplo, fornece um SHA no lugar de HEAD); no entanto git status, mostra muitos mods (presumivelmente porque o índice agora corresponde ao outro diretório e não à árvore de trabalho normal intocada). git resetvoltou a um bom estado.
Tom Goodfellow
2
O mesmo aqui git statusmostra muitos mods e git resetnão ajuda. Eu tive que git checkout -f HEADrestaurar o estado do meu repo.
DUzun
11
FYI: você precisa criar o diretório por conta própria, caso contrário, você receberá este erro:fatal: This operation must be run in a work tree
timaschew 02/02
13
Isso modifica desastrosamente o índice da árvore principal de trabalho, que normalmente é ruim. Como o @TomGoodfellow sugere, git resetbasta restaurar a sanidade da árvore principal de trabalho. Para exportar com segurança os subdiretórios do repositório em qualquer SHA1, ramificação ou tag sem modificar a árvore principal de trabalho, consulte a infame git archivesolução de Charles Bailey . Da mesma forma, para efetuar check-out com segurança de várias ramificações ao mesmo tempo, o novo git worktree addsubcomando é seu amigo.
Cecil Curry
25

Para um único arquivo:

git show HEAD:abspath/to/file > file.copy
Tobu
fonte
2
+1 e para esclarecer o "determinado commit anterior" (em vez de HEAD): refere-se ao SHA1 IDque pode ser encontrado facilmente via gitk. Se eu só precisa de "check-out" o arquivo para um local temporário (ou seja, não revertendo), então eu iria usar o showsubcomando:git show 82e54378856215ef96c5db1ff1160a741b5dcd70:MyProj/proguard/mapping.txt > myproj_mapping.txt
ef2011
19

As soluções acima não funcionaram para mim porque eu precisava verificar uma versão com tags específica da árvore. É assim cvs exportque deve ser usado, a propósito. git checkout-indexnão aceita o argumento tag, pois faz o check-out dos arquivos do índice. git checkout <tag>alteraria o índice independentemente da árvore de trabalho, então eu precisaria redefinir a árvore original. A solução que funcionou para mim foi clonar o repositório. O clone compartilhado é bastante rápido e não ocupa muito espaço extra. O .gitdiretório pode ser removido, se desejado.

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

Versões mais recentes do git devem suportar git clone --branch <tag>a verificação automática da tag especificada:

git clone --shared --branch <tag> <repository> <destination>
rm -rf <destination>/.git
proski
fonte
3
git --work-tree=/path/to/outputdir checkout <tag> -- .não funcionou para você?
warvariuc
1
Não, não faz. O arquivo real no diretório de trabalho original permanece inalterado, mas a versão preparada é perdida e substituída pela versão da tag. É especialmente ruim se a versão preparada contiver um conjunto de alterações cuidadosamente selecionado a ser confirmado. Não quero que o comando de exportação toque no meu índice, ponto final.
proski
19

Se você trabalha com seu recurso e não deseja fazer o checkout de volta ao master, execute:

cd ./myrepo

git worktree add ../myrepo_master master

git worktree remove ../myrepo_master

Ele criará um ../myrepo_masterdiretório com masterconfirmações de ramificação, onde você poderá continuar trabalhando

itsnikolay
fonte
1
Melhor resposta - simples e, ao contrário git --work-tree=/path/to/outputdir checkout HEAD -- ., não faz nada no índice, apenas copia a ramificação selecionada para o local especificado (com a adição de um arquivo .git).
Roger Dueck 25/10
E como eu desfiz essa mudança?
Scott P.
@ ScottP.just remove myrepo_masterdirectory
itsnikolay
1
desfazendo este é um subcomando da área de trabalho:git worktree remove ../myrepo_master
Martijn Dashorst
8

A resposta de Adrian lançou "fatal: esta operação deve ser executada em uma árvore de trabalho". A seguir, o que funcionou para nós.

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

Notas:

  • --no-checkout Não faça check-out de nada na nova árvore de trabalho.
  • --detach Não crie uma nova ramificação para a nova árvore de trabalho.
  • <some-ref>trabalha com qualquer ref, por exemplo, trabalha com HEAD~1.
  • Limpeza com git worktree prune.
Shaun Luttin
fonte
+1 por comentar sobre como limpar - todo mundo fica feliz em fazer uma bagunça no repo atual. somente este não tem efeitos colaterais.
Andrew Hill
1

Além da resposta de @ hasen . Para listar arquivos para checkout , você pode usar em git ls-filesvez de findgostar:

git ls-files -z *.txt | git checkout-index --prefix=/path-to/dest/ -f -z --stdin
snipsnipsnip
fonte
Obrigado por usar corretamente -z! É bom fornecer um script que não seja vulnerável a certos tipos de ataques de injeção.
ErikE
0

Eu defini um alias do git para conseguir exatamente isso (antes de encontrar essa pergunta).

É uma função bash curta que salva o caminho atual, alterna para o repositório git, faz um checkout e retorna onde começou.

git check para desenvolver ~ / my_project_git

Isso, por exemplo, faria o checkout do ramo de desenvolvimento no diretório "~ / my_project_git".

Este é o código alternativo dentro ~/.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
fonte
0

Estou usando esse alias para verificar uma ramificação em um diretório temporário:

[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

Uso:

git cot mybranch

Em seguida, você é solto em um novo shell no diretório temporário onde pode trabalhar na ramificação. Você pode até usar comandos git neste diretório.

Quando terminar, exclua o diretório e execute:

git worktree prune

Isso também é feito automaticamente no alias, antes de adicionar uma nova árvore de trabalho.

fdietze
fonte
0

Use git archive branch-index | tar -x -C your-folder-on-PCpara clonar uma ramificação em outra pasta. Eu acho que você pode copiar qualquer arquivo que precisar

dqthe
fonte