git: aplica los cambios introducidos por la confirmación en un repositorio a otro repositorio

115

Tengo un repo1y repo2en una máquina local. Son muy similares, pero esta última es algún tipo de otra rama ( repo1ya no se mantiene).

/path/to/repo1 $ git log HEAD~5..HEAD~4
<some_sha> Add: Introduce feature X

¿Cómo aplicar los cambios realizados por commit <some_sha>in repo1a repo2?

¿Necesito preparar algún parche o es posible hacerlo cherry-pickentre los repositorios?

¿Qué tal hacer lo mismo pero para un rango de confirmaciones?

tomando
fuente
2
¿No puedes simplemente pasar de repo1 a repo2?
zwol
para el caso un poco más específico en el que está buscando aplicar cambios a un archivo o archivos que se movieron en uno de los repositorios, mire aquí: stackoverflow.com/questions/3491270/…
Braham Snyder

Respuestas:

31

Como truco, puede intentar modificar la receta para comparar confirmaciones en dos repositorios diferentes en la página de GitTips , es decir:

GIT_ALTERNATE_OBJECT_DIRECTORIES=../repo/.git/objects \
git cherry-pick $(git --git-dir=../repo/.git rev-parse --verify <commit>)

donde ../repoes la ruta al otro repositorio.

Con Git moderno, puede usar múltiples revisiones y rangos de revisión con selección de cerebros .

El $(git --git-dir=../repo/.git rev-parse --verify <commit>) está aquí para traducir <commit>(por ejemplo HEAD, o v0.2, o master~2, que son valores en el segundo depósito de la copia se realiza) en SHA-1 identificador de comprometerse. Si conoce SHA-1 de un cambio que desea elegir, no es necesario.

TENGA EN CUENTA, sin embargo, que Git puede omitir la copia de objetos del repositorio de origen, ya que no sabe que el repositorio de objetos alternativo es solo temporal, para una operación. Es posible que deba copiar objetos del segundo repositorio con:

GIT_ALTERNATE_OBJECT_DIRECTORIES=../repo/.git/objects git repack -a -d -f

Esto coloca esos objetos prestados del segundo repositorio en el almacenamiento del repositorio original

No probado.


Una solución no tan hacky es seguir la respuesta de knittl :

  • Vaya al segundo repositorio desde el que desea copiar las confirmaciones y genere parches a partir de las confirmaciones que desee con git format-patch
  • Opcionalmente, copie los parches (0001- * etc.) a su repositorio
  • Úselo git am --3waypara aplicar parches
Jakub Narębski
fuente
1
Funciona bien. Si tiene problemas con la confirmación, haga 'git reset HEAD; git add. '.
gumik
5
esto es increíble, ¿cómo harías una serie de confirmaciones? solo sha1 ... sha2?
hvgotcodes
También obtengo, fatal: unable to read tree ...pero después de que git reset HEAD^todo funciona bien
jmarceli
@hvgotcodes funcionó para mí simplemente pasando el rango como, <commit>pero al rev-parse --verifycomando no le gusta, ya que solo acepta valores de confirmación únicos. Pero como cherry-pickacepta valores de compromiso únicos y de rango, pregunto: ¿por qué se rev-parsenecesita?
Chuim
1
@Chuim: git rev-parsees necesario si se desea hacer referencia a un compromiso por su nombre a base de referencia en otro depósito, por ejemplo master, HEAD^^o algo por el estilo; rev-parse lo convierte en un identificador universal SHA-1.
Jakub Narębski
207

Probablemente desee utilizar git format-patchy luego git amaplicar ese parche a su repositorio.

/path/to/1 $ git format-patch sha1^..sha1
/path/to/1 $ cd /path/to/2
/path/to/2 $ git am -3 /path/to/1/0001-…-….patch

O, en una línea:

/path/to/2 $ git --git-dir=/path/to/1/.git format-patch --stdout sha1^..sha1 | git am -3
Knittl
fuente
9
Esta solución resultó ser más simple y segura que la respuesta aceptada del uso directo de selección selectiva GIT_ALTERNATE_OBJECT_DIRECTORIES(que corrompería mi repositorio).
Chuim
2
Cuando hay conflictos, no funcionará porque no encuentra las confirmaciones en la otra rama.
Roger Far
2
Agregar --ignore-whitespaceal git amcomando puede resolver cualquier conflicto y evitar la necesidad de realizar una combinación de 3 vías
Hugheth
97

Puede hacerlo cherry-picksi agrega el segundo repositorio como remoto al primero (y luego fetch).

GUERRA
fuente
11
En realidad, esa es la forma correcta de hacerlo.
Wilbert
5
Este también me parece el camino correcto. Y simplemente lo usé y funcionó bien para mí.
Ricky Nelson
11
Prefiero decir: hazlo git fetch [remote-name]en el segundo repositorio y luego git cherry-pick [sha1].
5
Este enfoque funcionó muy bien para mí, gracias. Dado que el segundo repositorio también era local, solo tenía que usar un URI de archivo al agregarlo como remoto.
palimpsesto
2
En mi caso, tengo dos clones de un gigantesco repositorio remoto de git (para permitir el trabajo en paralelo), lo que significa que todo su historial ya está descargado y almacenado dos veces en mi HD. Si también tuviera que agregar cada uno como un control remoto del otro, eso crearía dos copias adicionales del mismo historial y potencialmente requeriría sincronizaciones entre ellas antes de poder hacerlo cherry-pick. Entonces, aunque pueda parecer la forma "correcta", no siempre es la más práctica.
Chuim