Cómo obtener solo un archivo de otra rama

1267

Estoy usando git y estoy trabajando en la rama maestra. Esta rama tiene un archivo llamado app.js.

Tengo una experimentrama en la que hice un montón de cambios y toneladas de confirmaciones. Ahora quiero traer todos los cambios realizados solo app.jsdesde from experimenthasta masterbranch.

¿Cómo puedo hacer eso?

Una vez más, no quiero una fusión. Solo quiero traer todos los cambios app.jsde experimentrama en masterrama.

Nick Vanderbilt
fuente
1
Respuesta excepcional y otros a partir de hoy responden cómo copiar el contenido del archivo, eso es lo que quería cuando encontré ese. Sin embargo, si se lee exactamente, Nick quería traer cambios, no texto completo, y el archivo masterpuede diferir experiment, por ejemplo, puede contener cambios combinados de otras ramas que se perderían en el archivo que se acaba de copiar. PS, por otro lado, no quiere fusionarse, pero hasta donde yo sé, el git mergetérmino es solo para rama, no para archivo específico, por lo que no hay contradicción aquí.
Alexei Martianov

Respuestas:

1605
git checkout master               # first get back to master
git checkout experiment -- app.js # then copy the version of app.js 
                                  # from branch "experiment"

¿Ver también git cómo deshacer cambios de un archivo?


Actualización de agosto de 2019, Git 2.23

Con los nuevos git switchy git restorecomandos, eso sería:

git switch master
git restore -s experiment -- app.js

Por defecto, solo se restaura el árbol de trabajo.
Si también desea actualizar el índice (es decir, restaurar el contenido del archivo y agregarlo al índice en un comando):

git restore -s experiment --staged --worktree -- app.js
# shorter:
git restore -s experiment -WS -- app.js

Como Jakub Narębski menciona en los comentarios:

git show experiment:path/to/app.js > path/to/app.js

también funciona, excepto que, como se detalla en la pregunta SO " ¿Cómo recuperar un solo archivo de una revisión específica en Git? ", debe usar la ruta completa desde el directorio raíz del repositorio.
De ahí la ruta / to / app.js utilizada por Jakub en su ejemplo.

Como Frosty menciona en el comentario:

solo obtendrá el estado más reciente de app.js

Pero, para git checkouto git show, en realidad puede hacer referencia a cualquier revisión que desee, como se ilustra en la pregunta SO " git checkout revision de un archivo en git gui ":

$ git show $REVISION:$FILENAME
$ git checkout $REVISION -- $FILENAME

sería lo mismo si $ FILENAME es una ruta completa de un archivo versionado.

$REVISIONpuede ser como se muestra en git rev-parse:

experiment@{yesterday}:app.js # app.js as it was yesterday 
experiment^:app.js            # app.js on the first commit parent
experiment@{2}:app.js         # app.js two commits ago

y así.

Schmijos agrega en los comentarios :

También puedes hacer esto desde un alijo:

git checkout stash -- app.js

Esto es muy útil si está trabajando en dos ramas y no quiere comprometerse.

VonC
fuente
13
Una nota: solo obtendrá el estado más reciente de app.js, no obtendrá ningún historial de la rama del experimento.
Frosty
2
@ThomasReggi debería poder importar (pagar) un archivo desde cualquier rama a cualquier rama actual. Si no puede, esa puede ser una buena pregunta para hacer aquí, con detalles específicos como el mensaje de error exacto y la versión de Git y OS utilizada.
VonC
2
En un subdirectorio, también puede usar experiment:./app.js. (No tiene que especificar la ruta completa). Aprendí esto gracias al mensaje de error muy útil que git me dio: "¿Quiso decir 'mybranch: full / path / to / my / file.xsl' aka 'mybranch: ./file.xsl '? " ¡Sí, lo hice! Creo que nunca me ha encantado tanto un mensaje de error fatal.
Evan Lenz
1
@TomaszGandor Sí, menciono que en stackoverflow.com/a/21066489/6309 , donde git show no modificaría el índice, pero git checkout modifica el índice.
VonC
1
@FriedBrice Vea mi respuesta: en estos días, seríagit restore -s new-feature path/to/app.js
VonC
360

Todo es mucho más simple, usa git checkout para eso.

Supongamos you're on masterbranch, para obtener app.js from new-featurebranch do:

git checkout new-feature path/to/app.js

// note that there is no leading slash in the path!

Esto le traerá el contenido del archivo deseado. Puede, como siempre, usar parte de sha1 en lugar del nombre de la rama de la nueva característica para obtener el archivo como estaba en esa confirmación en particular.

Nota : new-featuredebe ser una sucursal local , no remota.

Dmitry Avtonomov
fuente
78
Encuentro útil especificar siempre el origen git checkout origin/source_branch path/to/fileporque si ha descuidado actualizar la rama fuente de su repositorio local, puede obtener una versión anterior del archivo ... Pregúnteme cómo lo sé. ;)
Talyric
3
@Mymozaaa la pregunta no mencionaba los controles remotos, por lo tanto, la suposición de que es un repositorio puramente local
Dmitry Avtonomov
1
¿Este comando traerá el historial del archivo, o solo la última versión del archivo?
user1366265
1
@ user1366265 este comando colocará el archivo como estaba en la confirmación particular que especifique o el encabezado de la rama que especifique. No existe el "historial de un archivo", toda la información del historial solo se almacena en ramas.
Dmitry Avtonomov
3
Esto parece organizar automáticamente el archivo desprotegido. ¿Es posible hacer lo mismo sin escenificar?
bluenote10
44
git checkout branch_name file_name

Ejemplo:

git checkout master App.java

Esto no funcionará si el nombre de su sucursal tiene un punto.

git checkout "fix.june" alive.html
error: pathspec 'fix.june' did not match any file(s) known to git.
Sarath
fuente
@PhilipRego Esta respuesta es correcta. Supongo que hay una capitalización o puntuación diferente en su sucursal, o solo tiene una sucursal remota y no local. Vea el documento de pago de git: git-scm.com/docs/git-checkout#Documentation/…
Bret
@Bret Descubrí que no funciona cuando el nombre de la sucursal tiene un punto. Sugerí una edición
Philip Rego
Esta es la mejor respuesta. Desearía que esta respuesta fuera la mejor calificada. El más alto actual es muy confuso y no es sencillo
Russell Lego el
41

Complementario a las respuestas de VonC y chhh.

git show experiment:path/to/relative/app.js > app.js
# If your current working directory is relative than just use
git show experiment:app.js > app.js

o

git checkout experiment -- app.js
AlexLordThorsen
fuente
2
¡Frio! Odio especificar caminos largos. ¿El doble guión ( --) entre el nombre de la rama y las rutas es opcional? ¿Es solo para evitar que las rutas, que comenzarían con un guión, sean tratadas como opciones / interruptores?
Tomasz Gandor
Sinceramente no lo se. Ni siquiera me di cuenta de que había olvidado el doble guión hasta que lo señaló.
AlexLordThorsen
66
@TomaszGandor The --es opcional, pero es más útil para evitar conflictos con los nombres de las sucursales. Por ejemplo, git checkout -- foosignifica "retirar el archivo foo de HEAD" (es decir, sobrescribir los cambios locales en foo , es decir, un subconjunto de git reset --hard), pero git checkout foopodría significar eso o "vamos a ramificar foo ".
Alois Mahdal
8

O si desea todos los archivos de otra rama:

git checkout <branch name> -- .
Bufón
fuente
24
El queston inicial contiene "solo un archivo".
greatvovan
1
esto reemplaza los archivos existentes en lugar de fusionarse
Amare
3
Esto .hace una gran diferencia: en lugar de pasar a otra rama, copia todos los archivos desde allí mientras te deja en la actual. Obtiene contenido de otra rama sin entrar en él.
Xeverous
4

Revise el archivo en github y extráigalo desde allí.

Este es un enfoque pragmático que no responde directamente al OP, pero algunos han encontrado útil:

Si la rama en cuestión está en GitHub, puede navegar a la rama y el archivo deseados utilizando cualquiera de las muchas herramientas que ofrece GitHub, luego haga clic en 'Sin formato' para ver el texto plano y (opcionalmente) copie y pegue el texto como deseado.

Me gusta este enfoque porque le permite ver el archivo remoto en su totalidad antes de llevarlo a su máquina local.

temerario
fuente
2
Sin embargo, copiar y pegar el archivo sin formato puede causar cambios de caracteres no deseados en su git diff. Es más seguro guardar el archivo directamente en su proyecto para garantizar que no haya cambios.
Philip Rego
0

Si desea el archivo de una confirmación particular (cualquier rama), diga 06f8251f

git checkout 06f8251f path_to_file

por ejemplo, en windows:

git checkout 06f8251f C: \ A \ B \ C \ D \ file.h

arupjbasu
fuente
1
¡Gracias por tomarse el tiempo de responder! Pero esto no responde a la pregunta, y una buena respuesta que está muy detallada ya se publicó hace 9 años. No hay necesidad de cambiar la pregunta.
Nathan
Este es un escenario práctico válido. La respuesta trata correctamente con la rama, pero ¿qué hay de mirar una confirmación particular de la rama?
arupjbasu
0

Otra forma es crear un parche con las diferencias y aplicarlo en la rama maestra, por ejemplo. Digamos que la última confirmación antes de comenzar a trabajar en app.js es 00000aaaaa y la confirmación que contiene la versión que desea es 00000bbbbb

Luego de ejecutar esto en la rama de experimento:

git diff 00000aaaaa 00000bbbbb app.js > ~/app_changes.git

Esto creará un archivo con todas las diferencias entre esos dos commits para app.js que puede aplicar donde lo desee. Puede guardar ese archivo en cualquier lugar fuera del proyecto

Luego, en master solo ejecutas:

git apply ~/app_changes.git

ahora verá los cambios en los proyectos como si los hubiera hecho manualmente.

Santi
fuente
-3
git checkout master               -go to the master branch first
git checkout <your-branch> -- <your-file> --copy your file data from your branch.

git show <your-branch>:path/to/<your-file> 

Espero que esto te ayudará. Por favor, avíseme si tiene alguna consulta.

Rohit Saini
fuente