2012-03-19 6 views
17

Tengo dos ramas: troncal, producción. He encontrado un problema en el maletero, lo arreglé y lo comprometí, lo empujé. Ahora fue probado y necesito fusionar los cambios en la rama de producción como un arreglo caliente. Intento usar el cherry-pick. Sin embargo, no funciona porque un archivo cambiado en la corrección se renombró anteriormente en el tronco durante algunas refactorizaciones que no quiero poner en producción.Cambios de backport del archivo renombrado

No quiero fusionar todo, pero tome solo este compromiso. La selección de cereza falla con el conflicto "eliminado por nosotros" (por supuesto, el nuevo archivo nunca existió en la rama de producción).

¿Cuál es la forma correcta de llevar los cambios al archivo anterior?

Respuesta

11

que haría uso de buen parche viejo para esto:

git show COMMIT_ID -- old/file/name.txt | patch new/file/name.txt 
+1

Sí, funciona para mí. Sin embargo, sería interesante encontrar una solución mejor, particularmente en caso de que haya varios archivos renombrados. – kan

0

Esto es un poco complicado. Por ejemplo, puede crear un parche desde un diff y aplicarlo al archivo anterior. Pero en el futuro para evitar estos problemas, recomendaría hacer arreglos en la rama de producción y probarla allí primero, luego fusionarla desde la producción a la troncal.

+0

Sí, entiendo eso, sin embargo, no siempre es posible predecir lo que se va a solucionar. Estoy tratando de hacerlo a través de 'format-patch' /' apply-patch', pero no hace nada (no hay errores, tampoco cambios). Por favor, da una pista de la forma correcta de usarlo. – kan

+2

Echa un vistazo a la sección "Cambiar el nombre del manejo en git" en esta publicación http://blogs.atlassian.com/2011/10/confluence_git_rename_merge_oh_my/ – ralphtheninja

0

que experimentan el mismo problema y han tratado de encontrar una solución.

Lo resolví usando una secuencia de rebases. ¡No he realizado más pruebas que estas, así que utilícelas bajo su propio riesgo!

Si tu estás interesado echar un vistazo a que en github:

https://github.com/fraschfn/cherry-pick

2

Para selección de la cereza cambios de cualquier número de archivos, en caso de cambiar el nombre de un directorio entre las ramas:

git diff ... | sed -e 's|<old dir>|<new dir>|' | git apply - 
14

Si:

  • esperabas/esperaban que Git detectaría el movimiento o cambiar el nombre de el archivo en el tronco, pero no fue así, y
  • su repositorio tiene un número razonable de archivos

... entonces usted debería considerar cambiar su configuración de Git así:

$ git config merge.renameLimit 999999 

Es posible que durante un merge/cherry-pick, git llegue al límite de comprobación de archivos predeterminado (creo que es 400 o 1000 o algo así) antes de que sea capaz de encontrar la coincidencia de cambio de nombre adecuada. Al aumentar este límite, puede hacer que merge/cherry-pick tome más tiempo mientras busca su archivo renombrado, pero puede ayudar a evitar desafíos de fusión "eliminados por nosotros".

Eso debería ser el truco, pero si el archivo renombrado era pequeño y los cambios entre las ramas son significativos, también podría jugar con la configuración -X rename-threshold, p. bajando desde el 50% predeterminado con -X rename-threshold=25%.

+2

Una nota sobre 'rename-threshold' para otros usuarios: esto incluye todos los cambios a lo largo del tiempo. Tuve una fusión en la que el cambio de nombre original cambió dos líneas en el archivo, pero como se había modificado mucho * después de * ese punto, git todavía no detectó la similitud del archivo sin bajar 'rename-threshold'. – zebediah49

3

Ante el mismo problema, me preguntó un colega lo que haría, y su respuesta inmediata fue:

git checkout production 

git mv production-filename trunk-filename && git commit -m "Just fooling git" 
git cherry-pick trunk-commit 
git mv trunk-filename production-filename && git commit -m "Undo the damage" 

# Now squash the 3 commits 
git rebase -i HEAD~3 

funcionó como un encanto para mí.

+2

Esto funcionó de mí. Usé una GUI, pero seguí los mismos pasos. Me llevó un minuto averiguar qué está haciendo esto, así que enumeraré los pasos: 1. Cambie el nombre de los archivos/directorios en la rama de destino para que coincida con la rama fuente y confirmar. 2. Cherrypick el cambio de la rama fuente a la rama de destino. 3. Cambie el nombre de los archivos/directorios en la rama de destino a cómo fueron originalmente y confirme. 4. Aplaste esos 3 commits en un commit. – Tolli

0

Hice una secuencia de comandos de shell que intenta hacer una selección mientras se adivina el archivo se mueve (no funciona si cambió el nombre del archivo, solo si lo movió a otra carpeta): Sin embargo: actualmente lo hará fallar si la confirmación agrega nuevos archivos o si él mismo renombra los archivos.

#!/bin/bash 
# 
# Attemps to guess file moves (rename of folders) when cherry-pick'ing. 
# Gaspard van Koningsveld 
# 
[ "$1" == "" ] && echo "usage: $0 <commit-hash-to-cherry-pick>" && exit 1 
TMP_PATCH_FILE="temp-cherry-pick-patch" 
function abort() { 
    echo "Aborting" 
    "rm" -f "$TMP_PATCH_FILE" 
    exit 1 
} 
function main() { 
    echo "Retreiving commit patch..." 
    "git" show "$1" > "$TMP_PATCH_FILE" || abort 

    echo "Matching renamed files..." 
    sedcmds="" 
    for oldfile in $("grep" -E '(--- a|\+\+\+ b)' "$TMP_PATCH_FILE" | "cut" -c 7- | "sort" | "uniq"); do 
    [ -f "$oldfile" ] && continue 
    renamefound=0 
    oldfilepart="$oldfile" 
    while [ $renamefound -eq 0 ]; do 
     possiblefiles=$("git" ls-files "**/$oldfilepart") 
     if [ "$possiblefiles" != "" ]; then 
     if [ $("wc" -l <<< "$possiblefiles") == "1" ]; then 
      echo " $oldfile > $possiblefiles" 
      sedcmds="$sedcmds s|/$oldfile|/$possiblefiles|g;" 
      break 
     else 
      echo " ERROR: More than one rename possibility found for file $oldfile:" 
      echo "$possiblefiles" 
      abort 
     fi 
     fi 
     prevoldfilepart="$oldfilepart" 
     oldfilepart="${oldfilepart#*/}" 
     if [ "$prevoldfilepart" == "$oldfilepart" ]; then 
     echo " ERROR: Could not find rename for $oldfile." 
     abort 
     fi 
    done 
    done 
    echo "Renaming files in patch..." 
    "sed" -i "$sedcmds" "$TMP_PATCH_FILE" || abort 
    echo "Applying patch as new commit..." 
    "sed" -i "s/^commit /From commit /;s/^Author: /From: /" "$TMP_PATCH_FILE" || abort 
    "git" am -3 "$TMP_PATCH_FILE" 

    "rm" -f "$TMP_PATCH_FILE" 
} 
main "[email protected]" 
Cuestiones relacionadas