Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 51 additions & 49 deletions book/07-git-tools/sections/advanced-merging.asc
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ The format is called ``Combined Diff'' and gives you two columns of data next to

So in that example you can see that the `<<<<<<<` and `>>>>>>>` lines are in the working copy but were not in either side of the merge. This makes sense because the merge tool stuck them in there for our context, but we're expected to remove them.

If we resolve the conflict and run `git diff` again, we'll see the same thing, but it's a little more useful.
Si resolvemos el conflicto y corremos `git diff` de nuevo, veremos la misma cosa, pero es un poco más útil.

[source,console]
----
Expand All @@ -447,9 +447,9 @@ index 0399cd5,59727f0..0000000
hello()
----

This shows us that ``hola world'' was in our side but not in the working copy, that ``hello mundo'' was in their side but not in the working copy and finally that ``hola mundo'' was not in either side but is now in the working copy. This can be useful to review before committing the resolution.
Esto muestra que ``hola mundo'' estaba de nuestro lado, pero no en la copia de trabajo, que ``hello mundo'' estaba en el lado de ellos, pero no en la copia de trabajo y finalmente que ``hola mundo'' no estaba en ningún lado, sin embargo está ahora en la copia de trabajo. Esto puede ser útil para revisar antes de comprometer la resolución.

You can also get this from the `git log` for any merge after the fact to see how something was resolved after the fact. Git will output this format if you run `git show` on a merge commit, or if you add a `--cc` option to a `git log -p` (which by default only shows patches for non-merge commits).
También se puede obtener desde el `git log` para cualquier fusión después del hecho, para ver cómo algo se resolvió luego de este. Git dará salida a este formato si se puede correr `git show` en un compromiso de fusión, o si se añade la opción `--cc` a un `git log -p` (el cual por defecto solo muestras parches para compromisos no fusionados).

[source,console]
----
Expand Down Expand Up @@ -481,76 +481,76 @@ index 0399cd5,59727f0..e1d0799
----

[[_undoing_merges]]
==== Undoing Merges
==== Deshaciendo Fusiones

Now that you know how to create a merge commit, you'll probably make some by mistake.
One of the great things about working with Git is that it's okay to make mistakes, because it's possible (and in many cases easy) to fix them.
Ahora que ya conoces como crear un merge commit (compromiso de fusión), probablemente hayas creado algunos por error.
Una de las ventajas de trabajar con Git es que está bien cometer errores, porque es posible (y en muchos casos es fácil) solucionarlos.

Merge commits are no different.
Let's say you started work on a topic branch, accidentally merged it into `master`, and now your commit history looks like this:
Los compromisos de fusión no son diferentes.
Digamos que comenzaste a trabajar en una rama temática accidentalmente fusionada en una rama `master`, y ahora el historial de compromiso se ve así:

.Accidental merge commit
image::images/undomerge-start.png[Accidental merge commit.]

There are two ways to approach this problem, depending on what your desired outcome is.
Existen dos formas de abordar este problema, dependiendo de cuál es el resultado que deseas.

===== Fix the references
===== Solucionar las referencias

If the unwanted merge commit only exists on your local repository, the easiest and best solution is to move the branches so that they point where you want them to.
In most cases, if you follow the errant `git merge` with `git reset --hard HEAD~`, this will reset the branch pointers so they look like this:
Si el compromiso de fusión no deseado solo existe en tu repositorio local, la mejor y más fácil solución es mover las ramas para que así apunten a dónde quieres que lo hagan.
En la mayoría de los casos si sigues al errante `git merge` con `git reset --hard HEAD~`, esto restablecerá los punteros de la rama, así que se verá así:

.History after `git reset --hard HEAD~`
image::images/undomerge-reset.png[History after `git reset --hard HEAD~`.]

We covered `reset` back in <<_git_reset>>, so it shouldn't be too hard to figure out what's going on here.
Here's a quick refresher: `reset --hard` usually goes through three steps:
Ya vimos `restablecer` de nuevo en <<_git_reset>>, así que no debería ser muy difícil averiguar lo que está sucediendo ahí
Aquí un repaso rápido: `reset --hard` usualmente va a través de tres pasos:

. Move the branch HEAD points to.
In this case, we want to move `master` to where it was before the merge commit (`C6`).
. Make the index look like HEAD.
. Make the working directory look like the index.
. Mover los puntos de la rama HEAD.
En este caso, se quiere mover la `principal`a donde se encontraba antes el compromiso de fusión (`C6`).
. Hacer que el índice parezca HEAD.
. Hacer que el directorio de trabajo parezca el índice.

The downside of this approach is that it's rewriting history, which can be problematic with a shared repository.
Check out <<_rebase_peril>> for more on what can happen; the short version is that if other people have the commits you're rewriting, you should probably avoid `reset`.
This approach also won't work if any other commits have been created since the merge; moving the refs would effectively lose those changes.
La desventaja de este enfoque es que es reescribir el historial, lo cual puede ser problemático con un depósito compartido.
Revisa <<_rebase_peril>> para más de lo que puede suceder; la versión corta es que si otras personas tienen los compromisos que estas reescribiendo, probablemente deberías evitar `resetear`.
Este enfoque tampoco funcionará si cual quiera de los otros compromisos han sido creados desde la fusión; mover los refs efectivamente perdería esos cambios.

[[_reverse_commit]]
===== Reverse the commit
===== Revertir el compromiso

If moving the branch pointers around isn't going to work for you, Git gives you the option of making a new commit which undoes all the changes from an existing one.
Git calls this operation a ``revert'', and in this particular scenario, you'd invoke it like this:
Si mover los punteros de la rama alrededor no funciona para ti, Git te proporciona la opción de hacer un compromiso (commit) nuevo que deshace todos los cambios de uno ya existente.
Git llama a esta operación un ``revertir', y en este escenario en particular, has invocado algo así:

[source,console]
----
$ git revert -m 1 HEAD
[master b1d8379] Revert "Merge branch 'topic'"
----

The `-m 1` flag indicates which parent is the ``mainline'' and should be kept.
When you invoke a merge into `HEAD` (`git merge topic`), the new commit has two parents: the first one is `HEAD` (`C6`), and the second is the tip of the branch being merged in (`C4`).
In this case, we want to undo all the changes introduced by merging in parent #2 (`C4`), while keeping all the content from parent #1 (`C6`).
La bandera `-m 1` indica cuál padre es el ``mainline'' y debería ser mantenido.
Cuando se invoque la fusión en el `HEAD` (`git merge topic`), el nuevo compromiso tiene dos padres: el primero es `HEAD` (`C6`), y el segundo es la punta de la rama siendo fusionada en (`C4`).
En este caso, se quiere deshacer todos los cambios introducidos por el fusionamiento en el padre #2 (`C4`), mientras manteniendo todo el contenido del padre #1 (`C6`).

The history with the revert commit looks like this:
El historial con el compromiso revertido se ve así:

.History after `git revert -m 1`
image::images/undomerge-revert.png[History after `git revert -m 1`.]

The new commit `^M` has exactly the same contents as `C6`, so starting from here it's as if the merge never happened, except that the now-unmerged commits are still in `HEAD`'s history.
Git will get confused if you try to merge `topic` into `master` again:
El nuevo compromiso `^M` tiene exactamente los mismos contenidos que `C6`, así que comenzando desde aquí es como si la fusión nunca hubiese sucedido, excepto que la ahora los no fusionados compromisos están todavía en `HEAD`'s history.
Git se confundirá si intentas fusionar la rama `temática` en la rama `master`:

[source,console]
----
$ git merge topic
Already up-to-date.
----

There's nothing in `topic` that isn't already reachable from `master`.
What's worse, if you add work to `topic` and merge again, Git will only bring in the changes _since_ the reverted merge:
No hay nada en `topic` que no sea ya alcanzable para la `master`.
Que es peor, si añades trabajo a `topic` y fusionas otra vez, Git solo traerá los cambios desde la fusión revertida:

.History with a bad merge
image::images/undomerge-revert2.png[History with a bad merge.]

The best way around this is to un-revert the original merge, since now you want to bring in the changes that were reverted out, *then* create a new merge commit:
La mejor forma de evitar esto es deshacer la fusión original, dado que ahora se quiere traer los cambios que fueron revertidos, *luego* crear un nuevo compromiso de fusión:

[source,console]
----
Expand All @@ -562,22 +562,22 @@ $ git merge topic
.History after re-merging a reverted merge
image::images/undomerge-revert3.png[History after re-merging a reverted merge.]

In this example, `M` and `^M` cancel out.
`^^M` effectively merges in the changes from `C3` and `C4`, and `C8` merges in the changes from `C7`, so now `topic` is fully merged.
En este ejemplo, `M` y `^M` se cancelan.
Efectivamente `^^M` se fusiona en los cambios desde `C3` y `C4`, y `C8` se fusiona en los cambios desde `C7`, así que ahora `topic` está completamente fusionado.

==== Other Types of Merges
==== Otros Tipos de Fusiones

So far we've covered the normal merge of two branches, normally handled with what is called the ``recursive'' strategy of merging. There are other ways to merge branches together however. Let's cover a few of them quickly.
Hasta hora ya cubrimos la fusión normal de dos ramas, normalmente manejado con lo que es llamado la estrategia de fusión ``recursive''. Sin embargo, hay otras formas de fusionar a las ramas. Cubriremos algunos de ellos rápidamente.

===== Our or Theirs Preference
===== Nuestra o Su preferencia

First of all, there is another useful thing we can do with the normal ``recursive'' mode of merging. We've already seen the `ignore-all-space` and `ignore-space-change` options which are passed with a `-X` but we can also tell Git to favor one side or the other when it sees a conflict.
Primero que nada, hay otra cosa útil que podemos hacer con el modo de fusión ``recursive''. Ya se vio que las opciones `ignore-all-space` y `ignore-space-change` las cuales son pasadas con un `-X` pero también le podemos decir a Git que favorezca un lado u otro cuando observe un conflicto.

By default, when Git sees a conflict between two branches being merged, it will add merge conflict markers into your code and mark the file as conflicted and let you resolve it. If you would prefer for Git to simply choose a specific side and ignore the other side instead of letting you manually merge the conflict, you can pass the `merge` command either a `-Xours` or `-Xtheirs`.
Por defecto, cuando Git ve un conflicto entre dos ramas siendo fusionadas, añadirá marcadores de conflictos de fusión a los códigos y marca el archivo como conflictivo y te dejará resolverlo. Si prefieres que Git simplemente escoja un lado especifico e ignore el otro, en lugar de dejarte manualmente fusionar el conflicto, puedes pasar el comando de fusión ya sea un `-Xours` o `-Xtheirs`.

If Git sees this, it will not add conflict markers. Any differences that are mergeable, it will merge. Any differences that conflict, it will simply choose the side you specify in whole, including binary files.
Si Git ve esto, no añadirá marcadores de conflictos. Cualquier diferencia que pueda ser fusionable, se fusionará. Cualquier diferencia que entre en conflicto, él simplemente escogerá el lado que especifiques en su totalidad, incluyendo los archivos binarios.

If we go back to the ``hello world'' example we were using before, we can see that merging in our branch causes conflicts.
Si volvemos al ejemplo de ``hello world'' que estábamos utilizando antes, podemos ver que el fusionamiento en nuestra rama causa conflicto.

[source,console]
----
Expand All @@ -588,7 +588,7 @@ Resolved 'hello.rb' using previous resolution.
Automatic merge failed; fix conflicts and then commit the result.
----

However if we run it with `-Xours` or `-Xtheirs` it does not.
Sin embargo, si lo corremos con `-Xours` o `-Xtheirs` no lo causa.

[source,console]
----
Expand All @@ -601,13 +601,13 @@ Merge made by the 'recursive' strategy.
create mode 100644 test.sh
----

In that case, instead of getting conflict markers in the file with ``hello mundo'' on one side and ``hola world'' on the other, it will simply pick ``hola world''. However, all the other non-conflicting changes on that branch are merged successfully in.
En este caso, en lugar de obtener marcadores de conflicto en el archivo con ``hello mundo'' en un lado y ``hola world'' en el otro, simplemente escogerá ``hola world''. Sin embargo, todos los cambios no conflictivos en esa rama se fusionaron exitosamente.

This option can also be passed to the `git merge-file` command we saw earlier by running something like `git merge-file --ours` for individual file merges.
Esta opción también puede ser trasmitida al comando `git merge-file` que vimos antes al correr algo como esto `git merge-file --ours` para archivos de fusión individuales.

If you want to do something like this but not have Git even try to merge changes from the other side in, there is a more draconian option, which is the ``ours'' merge _strategy_. This is different from the ``ours'' recursive merge _option_.
Si quieres realizar algo así, pero Git no ha intentado siquiera fusionar cambios desde el otro lado, hay una opción más draconiana, la cual es la estrategia de fusión ``ours'' merge _strategy. Esto es diferente de la opción de fusión recursiva ``ours'' recursive merge _option_.

This will basically do a fake merge. It will record a new merge commit with both branches as parents, but it will not even look at the branch you're merging in. It will simply record as the result of the merge the exact code in your current branch.
Esto básicamente hace una fusión falsa. Registrará un nuevo compromiso de fusión con ambas ramas como padres, pero ni siquiera mirará a la rama que estas fusionando. Simplemente registrará como el resultado de la fusión el código exacto en tu rama actual.

[source,console]
----
Expand All @@ -617,8 +617,10 @@ $ git diff HEAD HEAD~
$
----

You can see that there is no difference between the branch we were on and the result of the merge.
Puedes observar que no hay diferencia entre la rama en la que estábamos y el resultado de la fusión.

Esto a menudo puede ser útil para básicamente engañar a Git para que piense que una rama ya ha sido fusionada cuando se hace una fusión más adelante. Por ejemplo, decir que has ramificado una rama de ``release'' y has hecho un poco de trabajo que querrás fusionar de vuelta en tu rama ``master'' en algún punto.
Mientras tanto, algunos arreglos de fallos en la ``master'' necesitan ser adaptados en la rama de `release`. Se puede fusionar la rama “bugfix” en la de `release` y también `merge -s ours`, la misma rama en la principal (a pesar de que el arreglo ya se encuentre ahí) Así que, más tarde cuando fusiones la de lanzamiento otra vez, no hay conflictos del bugfix.

This can often be useful to basically trick Git into thinking that a branch is already merged when doing a merge later on. For example, say you branched off a ``release'' branch and have done some work on it that you will want to merge back into your ``master'' branch at some point. In the meantime some bugfix on ``master'' needs to be backported into your `release` branch. You can merge the bugfix branch into the `release` branch and also `merge -s ours` the same branch into your `master` branch (even though the fix is already there) so when you later merge the `release` branch again, there are no conflicts from the bugfix.

include::subtree-merges.asc[]