GIT: Pago a una carpeta específica

128

Quiero usar algo similar a:

git checkout -- <path>/<file>

pero quiero retirar el archivo a alguna carpeta que elijo, en lugar de sobrescribir el local <path>/<file>.

¿Alguna idea?

Rafid
fuente

Respuestas:

57

Según Do "git export" (como "svn export")?

Puede usar git checkout-indexpara eso, este es un comando de bajo nivel, si desea exportar todo, puede usar -a,

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

Para citar las páginas del manual:

La "/" final [en el prefijo] es importante. El nombre exportado literalmente solo tiene como prefijo la cadena especificada.

Si desea exportar un determinado directorio, hay algunos trucos involucrados. El comando solo toma archivos, no directorios. Para aplicarlo a los directorios, use el comando 'buscar' y canalice la salida a git.

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

También de las páginas del manual:

La intuición no es el objetivo aquí. La repetibilidad es.

Hasen
fuente
Lamentablemente, esto no funcionará desde un repositorio de git desnudo, incluso con el --prefix set :-( (probado con git 1.9.1)
apeiros
1
si desea verificar una rama / confirmación de un repositorio git desnudo, useGIT_WORK_TREE=../path/to/place git checkout
allicoder
44
git worktree(ver abajo) imho es la respuesta canónica hoy y podría agregarse aquí.
geek-merlin
213

Otra solución que es un poco más limpia: simplemente especifique un árbol de trabajo diferente.

Para verificar todo, desde su HEAD (no índice) a un directorio de salida específico:

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

Para retirar un subdirectorio o archivo de su HEAD a un directorio específico:

git --work-tree=/path/to/outputdir checkout HEAD -- subdirname
Adrian Macneil
fuente
44
Nota menor: necesita una ruta absoluta ya que no se produce la expansión de la tilde de la cáscara, es decir, en --work-tree=/home/thomasg/okcopylugar de --work-tree=~/okcopy(posiblemente usar una ruta relativa mientras está sentado dentro del mismo árbol git también funciona, pero de esa manera yace la locura y las git statussalidas en R'lyehian)
Tom Goodfellow
10
Funciona como se esperaba con los commits antiguos también (por ejemplo, da un SHA en lugar de HEAD), sin embargo git status, muestra muchas modificaciones (presumiblemente porque el índice ahora coincide con el otro directorio y no con el árbol de trabajo normal sin tocar). git resetLo recuperé a un buen estado.
Tom Goodfellow
2
Lo mismo aquí git statusmuestra muchas modificaciones, y git resetno ayuda. Tuve git checkout -f HEADque restaurar el estado de mi repositorio.
DUzun
11
FYI: necesita crear el directorio usted mismo, de lo contrario obtendrá este error:fatal: This operation must be run in a work tree
timaschew 02 de
13
Esto modifica desastrosamente el índice del árbol de trabajo principal, que generalmente es malo. Como sugiere @TomGoodfellow, es git resetsuficiente para restaurar la cordura del árbol de trabajo principal. Para exportar con seguridad los subdirectorios de repositorio en cualquier SHA1, rama o etiqueta sin modificar el árbol de trabajo principal, consulte la infame git archivesolución de Charles Bailey . Del mismo modo, para pagar de forma segura varias sucursales al mismo tiempo, el nuevo git worktree addsubcomando es tu amigo.
Cecil Curry
25

Para un solo archivo:

git show HEAD:abspath/to/file > file.copy
Tobu
fuente
2
+1 y para aclarar sobre "cierta confirmación previa" (en lugar de HEAD): se refiere a la SHA1 IDque se puede encontrar fácilmente a través de gitk. Si solo necesito "retirar" ese archivo a una ubicación temporal (es decir, no revertirlo), entonces usaría el showsubcomando:git show 82e54378856215ef96c5db1ff1160a741b5dcd70:MyProj/proguard/mapping.txt > myproj_mapping.txt
ef2011
19

Las soluciones anteriores no funcionaron para mí porque necesitaba verificar una versión específica etiquetada del árbol. Así es como cvs exportse debe usar, por cierto. git checkout-indexno toma el argumento de la etiqueta, ya que extrae los archivos del índice. git checkout <tag>cambiaría el índice independientemente del árbol de trabajo, por lo que necesitaría restablecer el árbol original. La solución que funcionó para mí fue clonar el repositorio. El clon compartido es bastante rápido y no ocupa mucho espacio extra. El .gitdirectorio se puede eliminar si lo desea.

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

Las versiones más recientes de git deberían ser compatibles git clone --branch <tag>para verificar la etiqueta especificada automáticamente:

git clone --shared --branch <tag> <repository> <destination>
rm -rf <destination>/.git
proski
fuente
3
git --work-tree=/path/to/outputdir checkout <tag> -- .no funcionó para ti?
warvariuc
1
No lo hace El archivo real en el directorio de trabajo original no cambia, pero la versión por etapas se pierde y se reemplaza con la versión de la etiqueta. Es especialmente malo si la versión por etapas contenía un conjunto de cambios cuidadosamente seleccionados para ser confirmados. No quiero que el comando de exportación toque mi índice, punto.
proski
19

Si está trabajando con su función y no desea volver a pagar al maestro, puede ejecutar:

cd ./myrepo

git worktree add ../myrepo_master master

git worktree remove ../myrepo_master

Creará un ../myrepo_masterdirectorio con masterconfirmaciones de rama, donde puede continuar trabajando

itsnikolay
fuente
1
La mejor respuesta: simple y, a diferencia de git --work-tree=/path/to/outputdir checkout HEAD -- .que no hace nada al índice, simplemente copia la rama seleccionada en la ubicación especificada (con la adición de un archivo .git).
Roger Dueck
¿Y cómo deshacería este cambio?
Scott P.
@ ScottP.just remove myrepo_masterdirectory
itsnikolay
1
deshacer esto es un subcomando de worktree:git worktree remove ../myrepo_master
Martijn Dashorst el
8

La respuesta de Adrian arrojó "fatal: esta operación debe ejecutarse en un árbol de trabajo". Lo siguiente es lo que funcionó para nosotros.

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

Notas:

  • --no-checkout No verifique nada en el nuevo árbol de trabajo.
  • --detach No cree una nueva rama para el nuevo árbol de trabajo.
  • <some-ref>funciona con cualquier referencia, por ejemplo, funciona con HEAD~1.
  • Limpieza con git worktree prune.
Shaun Luttin
fuente
+1 por comentar sobre cómo limpiar: todos los demás están felices de hacer un lío con el repositorio actual. solo este no tiene efectos secundarios.
Andrew Hill
1

Además de la respuesta de @ hasen . Para hacer una lista de los archivos a pagar , es posible que desee usar en git ls-fileslugar de me findgusta:

git ls-files -z *.txt | git checkout-index --prefix=/path-to/dest/ -f -z --stdin
snipsnipsnip
fuente
Gracias por usar correctamente -z! Es bueno que proporcione un script que no sea vulnerable a ciertos tipos de ataques de inyección.
ErikE
0

Definí un alias de git para lograr esto (antes de encontrar esta pregunta).

Es una función bash corta que guarda la ruta actual, cambia al repositorio git, realiza un pago y regresa donde comenzó.

git check para desarrollar ~ / my_project_git

Esto, por ejemplo, verificaría la rama de desarrollo en el directorio "~ / my_project_git".

Este es el código de alias 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
fuente
0

Estoy usando este alias para verificar una rama en un directorio temporal:

[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

Luego se lo deja caer en un nuevo shell en el directorio temporal donde puede trabajar en la rama. Incluso puede usar comandos git en este directorio.

Cuando haya terminado, elimine el directorio y ejecute:

git worktree prune

Esto también se hace automáticamente en el alias, antes de agregar un nuevo árbol de trabajo.

fdietze
fuente
0

Use git archive branch-index | tar -x -C your-folder-on-PCpara clonar una rama a otra carpeta. Creo que puedes copiar cualquier archivo que necesites

dqthe
fuente