2009-09-10 37 views
40

¿Cómo se pueden combinar dos ramas en git, reteniendo archivos necesarios de una rama?git merge: Eliminando archivos que quiero mantener!

Al fusionar dos ramas, si se eliminó un archivo en una rama y no en otra, el archivo finalmente se elimina.

Por ejemplo:

  • Existe un archivo en el maestro cuando se hace una nueva rama
  • quita el archivo de maestro, ya que no es (aún) necesitamos
  • se realizan cambios en la rama para añadir una característica, que se basa en el archivo existente
  • hacer correcciones de errores en el maestro (no puede ser descartada)
  • te fusionas algún día, ¡y el archivo ya no está!

Cómo reproducir:

  1. Crear un repositorio git con un archivo.

    git init 
    echo "test" > test.txt 
    git add . 
    git commit -m "initial commit" 
    
  2. Crear una rama

    git branch branchA 
    
  3. Eliminar el archivo maestro en

    git rm test.txt 
    git commit -m "removed file from master" 
    
  4. hacer cualquier cambio en branchA que no tocan el archivo eliminado (que tiene que ser sin cambios para evitar Conflictos)

    git checkout branchA 
    touch something.txt 
    git add . 
    git commit -m "some branch changes" 
    

Desde aquí, de cualquier manera que he encontrado para fusionar estas dos ramas, se elimina el archivo test.txt. Suponiendo que estábamos confiando en el archivo para branchA, este es un gran problema.


ejemplos Failing:

Combinar 1

git checkout branchA 
git merge master 
ls test.txt 

Combinar 2

git checkout master 
git merge branchA 
ls test.txt 

Rebase 1

git checkout branchA 
git rebase master 
ls test.txt 
+0

Creo que se puede resolver este problema mediante el rebase branchA (siempre y cuando no sea pública) del último maestro antes de la fusión. Una base de datos interactiva le dará la oportunidad de decirle a git que definitivamente desea el archivo, luego la fusión debería realizarse sin problemas. – jchook

Respuesta

21

Esto es un problema interesante. Debido a que eliminó el archivo después de que se creó BranchA, y luego está fusionando master en BranchA, no estoy seguro de cómo Git podría darse cuenta de que hay un conflicto.

Después de la mala combinación que se puede deshacer, y luego volver a la fusión, pero volver a agregar el archivo:

git checkout [email protected]{1} . 
git merge --no-commit master 
git checkout master test.txt 
git add test.txt 
git commit 
+9

copiar manualmente y volver a agregar el archivo (s) sería una buena solución, pero me gustaría saber cómo hacerlo a través de git. Si la respuesta de git a este problema de bifurcación/fusión es "hacer una copia de seguridad y hacerlo usted mismo", prácticamente no tiene mis razones para usar git. – drfloob

+3

no, no necesita una copia de seguridad manual. Puede sacar el archivo de la rama principal. Actualicé el ejemplo. – cmcginty

+0

¿Qué significa HEAD @ {1}? – shampoo

4

Para una solución rápida en este caso, "git revert" la confirmación de que elimina el archivo.

Cuando surja esta situación en el futuro, la mejor manera de manejarla es garantizar que la creación del nuevo archivo ocurra en la sucursal. Luego se agrega en el maestro cuando se fusiona, pero mientras tanto no tiene el archivo en el maestro.

+0

la confirmación que eliminó el archivo (s) incluyó otros cambios no triviales. git-revert no parece ser una opción, ya que no puedo perder esos otros cambios. – drfloob

+4

En ese caso, la manera más fácil podría ser hacer "git revert -n [commit]", que parcha en todos los cambios pero no los compromete. Luego use "git checkout HEAD [filenames]" para borrar los cambios que no desea, es decir, todo excepto la restauración del archivo, luego confirme. – Phil

2

Debe modificar el archivo en la bifurcación, de modo que exista un conflicto de fusión con la eliminación en la línea externa.

Lo mismo sucederá si, por ejemplo, elimina una declaración de algo en un archivo de cabecera en el tronco (porque nada lo necesita), y agrega una dependencia a esa declaración a algunos archivos sin encabezado (s) en la rama Cuando se fusiona, dado que la rama no toca (esa parte del) encabezado, simplemente eliminará la declaración y las cosas se romperán.

Siempre que tenga cosas en varios lugares que sean interdependientes y necesiten mantenerse sincronizadas, es muy fácil fusionarlas para introducir problemas silenciosamente. Es solo una de las cosas que debe saber y verificar cuando se fusiona. Lo ideal es utilizar afirmaciones en tiempo de compilación u otras comprobaciones del tiempo de compilación que harán que las fallas aparezcan inmediatamente.

3

ejemplo Casey 's no funcionó para mi caso - no podía pago y envío test.txt de master, porque ya no estaba en esa rama:

$ git checkout master test.txt 
error: pathspec 'test.txt' did not match any file(s) known to git. 

Felizmente pude tirar del archivo fuera de branchA 's propia HEAD:

$ git checkout branchA 
$ git merge --no-commit master 
$ git checkout HEAD test.txt 
$ git add test.txt 
$ git commit 
+0

¿Cómo hacer si tengo miles de archivos para agregar? – kabrice

0

Mi solución a esto fue simplemente modificar los archivos que necesitaba para mantener (añadido un comentario que era necesario de todos modos) y comprometerse esos cambios en la rama de destino, generando así un conflicto de fusión que podría resolverse fácilmente con un git add y una confirmación normal.

Mi historia fue algo como esto. Los nombres de las sucursales han sido cambiados para proteger a los inocentes.

  1. crear y cometer archivos para una nueva función para dominar
  2. dan cuenta de esto, además va a ser más complicado de lo previsto inicialmente, por lo tanto, ramificado a feature_branch
  3. archivos eliminados de maestro a fin de no interrumpir el flujo normal de trabajo con RBS y tal
  4. el tiempo pasa, más confirmaciones sobre el master, ninguno de feature_branch
  5. trabajo
  6. Reanudar de la función, git merge master en feature_branch hace que los archivos originales a ser eliminado (por supuesto), a git reset --hard antes de la fusión
  7. aplicado la solución descrita anteriormente