¿Es posible elegir un commit desde otro repositorio git?

726

Estoy trabajando con un repositorio git que necesita una confirmación de otro repositorio git que no sabe nada del primero.

Por lo general, elegiría con cereza usando el HEAD@{x}en el registro, pero debido a que esto .gitno sabe nada de esta entrada de registro (directorio físico diferente), ¿cómo puedo seleccionar esto, o puedo?

Estoy usando git-svn. Mi primera rama está usando git-svnel trunkde un repositorio de Subversion, y la siguiente rama está usando git-svnuna rama de Subversion.

gitcoder182
fuente
2
Esta es la razón dada por Ben Lee para abrir una recompensa por esta pregunta: "Voy a otorgar la recompensa por la respuesta correcta, en lugar de la respuesta aceptada. Solo tengo que esperar 24 [horas] para hacerlo". Sin embargo, no entiendo cuál de estos se supone que es "la respuesta correcta" y por qué la respuesta aceptada no es "correcta".
1
No está claro cuál es la naturaleza del problema. ¿Cómo se relacionan estos repositorios diferentes, si es que lo hacen? ¿Es uno un tenedor de otro? ¿O son en realidad dos proyectos completamente separados y no relacionados?
@Cupcake, la respuesta aceptada es buena y claramente ayudó al OP, por lo que debe aceptarse. Por "correcto" en realidad solo quise decir "adecuado para mí" (y a juzgar por los comentarios, correcto para varias otras personas también). Solo pensé que el que le di la recompensa merecía tanta reputación como la respuesta aceptada.
Ben Lee

Respuestas:

557

Tendrá que agregar el otro repositorio como un control remoto y luego buscar sus cambios. Desde allí ves el commit y puedes elegirlo.

Como eso:

git remote add other https://example.link/repository.git
git fetch other

Ahora tiene toda la información para hacer simplemente git cherry-pick.

Más información sobre cómo trabajar con controles remotos aquí: https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes

CharlesB
fuente
1
¿Qué pasa si estoy usando git-svn? mi primera rama está usando git-svn del tronco y la próxima está utilizando el git-svn en una rama (gracias por la rápida respuesta)
gitcoder182
1
Cuando clone por primera vez el repositorio de Subversion, asegúrese de clonar todo el repositorio, no solo el tronco. También asegúrese de usar la --stdlayoutopción de git-svn si está usando el diseño estándar de troncal / ramas / etiquetas en Subversion. Entonces la rama Subversion será una mera rama remota de git.
wilhelmtell
33
Si está utilizando Github, puede extraer el parche agregando .patch a la URL de confirmación y luego aplicándolo con git am < d821j8djd2dj812.patch. Fuera de GH, se podrían hacer conceptos similares como se menciona en la respuesta alternativa a continuación.
Radicando
2
@radicand, ¿qué respuesta a continuación es la "alternativa"? Por favor, enlace a él.
77
Pasos detallados para elegir desde otro repositorio: coderwall.com/p/sgpksw/git-cherry-pick-from-another-repository
T. Kim Nguyen
854

La respuesta, como se da, es usar el parche de formato, pero dado que la pregunta era cómo seleccionar con precisión desde otra carpeta, aquí hay un código para hacer exactamente eso:

$ git --git-dir=../<some_other_repo>/.git \
format-patch -k -1 --stdout <commit SHA> | \
git am -3 -k

(explicación de @cong ma )

El git format-patchcomando crea un parche a partir some_other_repode la confirmación especificada por su SHA ( -1solo para una confirmación). Este parche se canaliza a git am, que aplica el parche localmente ( -3significa intentar la fusión tripartita si el parche no se aplica de manera limpia). Espero que eso explique.

Robert Wahler
fuente
18
Esto es perfecto, pero sería genial si alguien pudiera ampliar esto: un desglose de lo que está sucediendo exactamente (especialmente con esas banderas) sería increíblemente útil.
Nick F
46
@NickF, el git format-patchcomando crea un parche a partir some_other_repode la confirmación especificada por su SHA ( -1solo para una confirmación). Este parche se canaliza a git am, que aplica el parche localmente ( -3significa intentar la fusión tripartita si el parche no se aplica de manera limpia). Espero que eso explique.
Cong Ma
3
error: parche fallido: somefile.cs: 85 error: somefile.cs: el parche no se aplica ¿Editó manualmente su parche? No se aplica a los blobs registrados en su índice. No puede recurrir a la fusión a tres bandas. El parche falló en 0001 Piezas de GUI agregadas La copia del parche que falló se encuentra en: <some_other_repo> /.git/rebase-apply/patch Cuando haya resuelto este problema, ejecute "git am --continue". Si prefiere omitir este parche, ejecute "git am --skip" en su lugar. Para restaurar la rama original y detener el parcheo, ejecute "git am --abort".
Tom
8
@ Tom intenta usar --ignore-whitespace. Comando completo: git --git-dir=../<some_other_repo>/.git format-patch -k -1 --stdout <commit SHA> | git am -3 -k --ignore-whitespace
Jake Graham Arnold
77
@BoomShadow Porque es mucho más simple. Agregar el control remoto y buscar trae todos los cambios del otro repositorio. Esta línea de comando es una acción única.
Jonathon Reinhart
152

Aquí hay un ejemplo de la combinación remote-fetch-merge.

cd /home/you/projectA
git remote add projectB /home/you/projectB
git fetch projectB

Entonces tú puedes:

git cherry-pick <first_commit>..<last_commit>

o incluso podrías fusionar toda la rama

git merge projectB/master
Brian
fuente
54
git merge projectB/master es muy, muy mal , porque no se va a aplicar los cambios de una sola comprometen (como una cereza-escoge lo haría), que en realidad estás en la fusión de todos los cambios en losprojectB/masterque no están contenidas en su propiamasterrama.
44
Supuse que esta era la intención del cartel original. De lo contrario, sí, esta no es la opción correcta para ellos.
Brian
55
Esto funciona de manera brillante cuando los dos repositorios están relacionados.
Ronny Ager-Wick
1
He creado una copia de un repositorio de git (solo para "jugar" sin romper el repositorio original) y para mantenerlo actualizado con su fuente, la respuesta de Brian es exactamente lo que necesitaba, así que, Cupcake, yo Tengo que decir que no está "mal", sino otro caso de uso. Pero es agradable de su parte señalar el posible desastre: D
ferrari2k
66
En mi opinión, esta debe ser la solución aceptada. Además, si desea eliminar el control remoto una vez que haya terminado de seleccionarlo, úselo git remote rm projectB. También se usa git tag -d tag-namepara eliminar las etiquetas obtenidas del repositorio remoto. Las confirmaciones remotas ya no se mostrarán en su historial, y la poda eventualmente las eliminará del almacenamiento.
ADTC
130

Puedes hacerlo, pero requiere dos pasos. Así es cómo:

git fetch <remote-git-url> <branch> && git cherry-pick FETCH_HEAD

Reemplazar <remote-git-url> con la url o la ruta al repositorio desde el que desea seleccionar cherry.

Reemplazar <branch> con el nombre de la rama o etiqueta que desea seleccionar desde el repositorio remoto.

Usted puede reemplazar FETCH_HEAD con un git SHA de la rama.

Actualizado: modificado según los comentarios de @ pkalinow.

docwhat
fuente
8
Funciona con un nombre de sucursal, pero no con SHA. Si desea cereza recoger una confirmación denotado por su hash, utilice en su lugar: git fetch <repo-url> <branch> && git cherry-pick <sha>.
pkalinow
Gracias. Esto era justo lo que necesitaba para insertar una serie de confirmaciones de un repositorio a otro, que creé para este propósito.
wojciii
Esto era exactamente lo que necesitaba con muchas implementaciones personalizadas de nuestro código para diferentes clientes (que tienen sus propios repositorios / bifurcaciones), necesitábamos una forma de obtener confirmaciones específicas en nuestra base / troncal. ¡GRACIAS!
RedSands
Esta debería ser la respuesta aceptada para una selección de cereza de una sola vez en los repositorios. Lo uso todo el tiempo cuando elijo entre repositorios que ya son locales, la URL remota es solo una ruta de sistema de archivos local.
Amedee Van Gasse
61

Estos son los pasos para agregar un control remoto, buscar ramas y seleccionar una confirmación

# Cloning our fork
$ git clone [email protected]:ifad/rest-client.git

# Adding (as "endel") the repo from we want to cherry-pick
$ git remote add endel git://github.com/endel/rest-client.git

# Fetch their branches
$ git fetch endel

# List their commits
$ git log endel/master

# Cherry-pick the commit we need
$ git cherry-pick 97fedac

Fuente: https://coderwall.com/p/sgpksw

jaredwilli
fuente
17

Vea Cómo crear y aplicar un parche con Git . (Según la redacción de su pregunta, supuse que este otro repositorio es para una base de código completamente diferente. Si es un repositorio para la misma base de código, debe agregarlo como un control remoto como lo sugiere @CharlesB. Incluso si es para otro base de código, supongo que aún podría agregarlo como un control remoto, pero es posible que no desee obtener toda la rama en su repositorio ...)

Aasmund Eldhuset
fuente
11

Puede hacerlo en una línea de la siguiente manera. Espero que esté en el repositorio de git que necesita el cambio seleccionado y que haya verificado para corregir la rama.

git fetch ssh://[email protected]:7999/repo_to_get_it_from.git branchToPickFrom && git cherry-pick 02a197e9533
# 

git fetch [URL de la sucursal] [Branch to cherry-pick from] && git cherry-pick [commit ID]

Don
fuente
1
Saludos, no necesitaba la ssh://parte, solo parahttps://
Leo
5

Si. Obtenga el repositorio y luego seleccione desde la rama remota.

Wilhelmtell
fuente
1

Suponiendo que Ase reporto que desea cereza elegir, y Bes el que desea quedarse con la escoja para, usted puede hacer esto mediante la adición </path/to/repo/A/>/.git/objectsa </path/to/repo/B>/.git/objects/info/alternates. Crea estoalternates archivos si no existe.

Esto hará que el repositorio B acceda a todos los objetos git del repositorio A, y hará que la selección de cerezas funcione para usted.

pranavk
fuente
0

Mi situación fue que tengo un repositorio al que el equipo empuja, y un clon de eso sentado justo al lado. Este conjunto de líneas en un Makefile funciona correctamente para mí:

git reset --hard
git remote update --prune
git pull --rebase --all
git cherry-pick -n remotes/origin/$(BRANCH)

Al mantener actualizado al maestro del repositorio desnudo, podemos elegir un cambio propuesto publicado en el repositorio desnudo. También tenemos una forma (más complicada) de seleccionar múltiples braches para una revisión y prueba consolidadas.

Si "no sabe nada" significa "no se puede usar como un control remoto", entonces esto no ayuda, pero esta pregunta SO surgió cuando busqué en Google para crear este flujo de trabajo, así que pensé que podría contribuir de nuevo.

Paul Hulett
fuente
-n significa no-commit según git docs y creo que es muy importante ver los cambios antes de hacer un commit
canbax
0

Si desea seleccionar varias confirmaciones para un archivo determinado hasta llegar a una confirmación determinada, utilice lo siguiente.

# Directory from which to cherry-pick
GIT_DIR=...
# Pick changes only for this file
FILE_PATH=...
# Apply changes from this commit
FIST_COMMIT=master
# Apply changes until you reach this commit
LAST_COMMIT=...

for sha in $(git --git-dir=$GIT_DIR log --reverse --topo-order --format=%H $LAST_COMMIT_SHA..master -- $FILE_PATH ) ; do 
  git --git-dir=$GIT_DIR  format-patch -k -1 --stdout $sha -- $FILE_PATH | 
    git am -3 -k
done
Diomidis Spinellis
fuente