remota - git push
Combine, actualice y extraiga sucursales de Git sin usar cajas. (10)
La respuesta corta
Mientras esté haciendo una combinación de avance rápido , simplemente puede usar
git fetch <remote> <sourceBranch>:<destinationBranch>
Ejemplos:
# Merge local branch foo into local branch master,
# without having to checkout master first.
# Here `.` means to use the local repository as the "remote":
git fetch . foo:master
# Merge remote branch origin/foo into local branch foo,
# without having to checkout foo first:
git fetch origin foo:foo
Si bien la respuesta de Amber también funcionará en casos de avance rápido, usar git fetch
de esta manera es un poco más seguro que solo mover la fuerza de la referencia, ya que git fetch
evitará automáticamente el avance no rápido hacia adelante siempre que no lo hagas. t usar +
en la refspec.
La respuesta larga
No puede fusionar una rama B en la rama A sin desproteger A primero si esto resultaría en una combinación sin avance rápido. Esto se debe a que se necesita una copia de trabajo para resolver cualquier conflicto potencial.
Sin embargo, en el caso de fusiones rápidas, esto es posible , porque tales fusiones nunca pueden dar lugar a conflictos, por definición. Para hacer esto sin verificar primero una rama, puede usar git fetch
con un refspec.
Este es un ejemplo de la actualización del master
(que no permite cambios que no se adelantan) si tiene otra feature
bifurcación activada:
git fetch upstream master:master
Este caso de uso es tan común, que probablemente querrá hacer un alias para él en su archivo de configuración de git, como este:
[alias]
sync = !sh -c ''git checkout --quiet HEAD; git fetch upstream master:master; git checkout --quiet -''
Lo que hace este alias es lo siguiente:
git checkout HEAD
: esto pone su copia de trabajo en un estado de cabeza separada. Esto es útil si desea actualizar elmaster
mientras que lo tiene desprotegido. Creo que era necesario hacerlo porque, de lo contrario, la referencia de bifurcación para elmaster
no se moverá, pero no recuerdo si eso es realmente correcto.git fetch upstream master:master
: envía rápidamente tumaster
local al mismo lugar queupstream/master
.git checkout -
revisa su sucursal previamente retirada (eso es lo que hace en este caso).
La sintaxis de git fetch
para fusiones (no) de avance rápido
Si desea que el comando fetch
falle si la actualización no avanza rápidamente, simplemente use una refspec del formulario
git fetch <remote> <remoteBranch>:<localBranch>
Si desea permitir actualizaciones que no sean de avance rápido, entonces agregue un +
al frente de la refspec:
git fetch <remote> +<remoteBranch>:<localBranch>
Tenga en cuenta que puede pasar su repositorio local como parámetro "remoto" usando .
:
git fetch . <sourceBranch>:<destinationBranch>
La documentación
De la documentación de git fetch
que explica esta sintaxis (el énfasis es mío):
<refspec>
El formato de un parámetro
<refspec>
es un signo más+
opcional, seguido de la referencia de origen<src>
, seguido de dos puntos:
seguido de la referencia de destino<dst>
.La referencia remota que coincide con
<src>
se recupera, y si<dst>
no es una cadena vacía, la referencia local que coincide con ella se adelanta rápidamente utilizando<src>
. Si se utiliza el plus+
opcional, la referencia local se actualiza incluso si no resulta en una actualización de avance rápido.
Ver también
Trabajo en un proyecto que tiene 2 ramas, A y B. Normalmente trabajo en la rama A, y fusiono cosas de la rama B. Para la fusión, normalmente haría:
git merge origin/branchB
Sin embargo, también me gustaría conservar una copia local de la sucursal B, ya que ocasionalmente puedo revisar la sucursal sin fusionarme primero con mi sucursal A. Para esto, haría:
git checkout branchB
git pull
git checkout branchA
¿Hay una manera de hacer lo anterior en un comando, y sin tener que cambiar de bifurcación? ¿Debo usar git update-ref
para eso? ¿Cómo?
Como dijo Amber, las combinaciones de avance rápido son el único caso en el que posiblemente podrías hacer esto. Cualquier otra combinación que se pueda imaginar debe pasar por la combinación de tres vías, aplicar parches, resolver conflictos, y eso significa que debe haber archivos.
Resulta que tengo una secuencia de comandos que utilizo exactamente para esto: hacer combinaciones de avance rápido sin tocar el árbol de trabajo (a menos que se esté fusionando con HEAD). Es un poco largo, porque es al menos un poco robusto; verifica que la fusión sea un avance rápido, luego lo realiza sin verificar la rama, pero produce los mismos resultados que si tuviera, ve el diff --stat
resumen de los cambios de diff --stat
, y la entrada en el reflog es exactamente como una combinación de avance rápido, en lugar del "reset" que se obtiene si se usa branch -f
. Si lo nombra git-merge-ff
y lo coloca en su directorio bin, puede llamarlo como un comando git merge-ff
: git merge-ff
.
#!/bin/bash
_usage() {
echo "Usage: git merge-ff <branch> <committish-to-merge>" 1>&2
exit 1
}
_merge_ff() {
branch="$1"
commit="$2"
branch_orig_hash="$(git show-ref -s --verify refs/heads/$branch 2> /dev/null)"
if [ $? -ne 0 ]; then
echo "Error: unknown branch $branch" 1>&2
_usage
fi
commit_orig_hash="$(git rev-parse --verify $commit 2> /dev/null)"
if [ $? -ne 0 ]; then
echo "Error: unknown revision $commit" 1>&2
_usage
fi
if [ "$(git symbolic-ref HEAD)" = "refs/heads/$branch" ]; then
git merge $quiet --ff-only "$commit"
else
if [ "$(git merge-base $branch_orig_hash $commit_orig_hash)" != "$branch_orig_hash" ]; then
echo "Error: merging $commit into $branch would not be a fast-forward" 1>&2
exit 1
fi
echo "Updating ${branch_orig_hash:0:7}..${commit_orig_hash:0:7}"
if git update-ref -m "merge $commit: Fast forward" "refs/heads/$branch" "$commit_orig_hash" "$branch_orig_hash"; then
if [ -z $quiet ]; then
echo "Fast forward"
git diff --stat "$branch@{1}" "$branch"
fi
else
echo "Error: fast forward using update-ref failed" 1>&2
fi
fi
}
while getopts "q" opt; do
case $opt in
q ) quiet="-q";;
* ) ;;
esac
done
shift $((OPTIND-1))
case $# in
2 ) _merge_ff "$1" "$2";;
* ) _usage
esac
PD: ¡Si alguien ve algún problema con ese script, por favor comente! Era un trabajo de escribir y olvidar, pero estaría feliz de mejorarlo.
En tu caso puedes usar
git fetch origin branchB:branchB
que hace lo que usted desea (asumiendo que la fusión es un avance rápido). Si la rama no se puede actualizar porque requiere una combinación de no avance rápido, esto falla con seguridad con un mensaje.
Esta forma de búsqueda tiene algunas opciones más útiles también:
git fetch <remote> <sourceBranch>:<destinationBranch>
Tenga en cuenta que <remote>
puede ser un repositorio local , y <sourceBranch>
puede ser una rama de seguimiento. Por lo tanto, puede actualizar una sucursal local, incluso si no está desprotegida, sin acceder a la red .
Actualmente, mi acceso al servidor ascendente es a través de una VPN lenta, por lo que periódicamente me conecto, git fetch
para actualizar todos los controles remotos y luego me desconecto. Entonces si, digamos, el maestro remoto ha cambiado, puedo hacerlo
git fetch . remotes/origin/master:master
para actualizar de manera segura a mi maestro local, incluso si actualmente tengo alguna otra sucursal desprotegida. No se requiere acceso a la red.
Escribí una función de shell para un caso de uso similar que encuentro diariamente en proyectos. Esto es básicamente un atajo para mantener las sucursales locales al día con una sucursal común como desarrollar antes de abrir un RP, etc.
Publicar esto aunque no quiera usar el proceso de
checkout
, en caso de que a otros no les importe esa restricción.
glmh
("git pull and merge here") checkout branchB
automáticamente la checkout branchB
, checkout branchB
la última, checkout branchA
y merge branchB
No aborda la necesidad de mantener una copia local de la sucursal A, pero podría modificarse fácilmente para hacerlo agregando un paso antes de retirar la sucursal B. Algo como...
git branch ${branchA}-no-branchB ${branchA}
Para simples fusiones de avance rápido, esto salta al indicador de mensaje de confirmación.
Para las fusiones que no son de avance rápido, esto coloca a su sucursal en el estado de resolución de conflictos (es probable que deba intervenir).
Para la configuración, agregue a .bashrc
o .zshrc
, etc:
glmh() {
branchB=$1
[ $# -eq 0 ] && { branchB="develop" }
branchA="$(git branch | grep ''*'' | sed ''s/* //g'')"
git checkout ${branchB} && git pull
git checkout ${branchA} && git merge ${branchB}
}
Uso:
# No argument given, will assume "develop"
> glmh
# Pass an argument to pull and merge a specific branch
> glmh your-other-branch
Nota: Esto no es lo suficientemente robusto como para transferir args más allá del nombre de la rama a
git merge
Introduzca git-forward-merge :
Sin necesidad de desproteger destino,
git-forward-merge <source> <destination>
combina el origen en la rama de destino.
https://github.com/schuyler1d/git-forward-merge
Solo funciona para las combinaciones automáticas, si hay conflictos, debe utilizar la combinación regular.
No no hay. Una verificación de la rama de destino es necesaria para permitirle resolver conflictos, entre otras cosas (si Git no puede fusionarlos automáticamente).
Sin embargo, si la combinación es de avance rápido, no necesita revisar la rama de destino, ya que en realidad no necesita combinar nada, todo lo que debe hacer es actualizar la rama para que apunte a la rama. nueva cabeza ref. Puedes hacer esto con git branch -f
:
git branch -f branch-b branch-a
Actualizaré la branch-b
para que apunte al jefe de la branch-a
.
La opción -f
significa --force
, lo que significa que debe tener cuidado al usarla. No lo use a menos que esté seguro de que la fusión será un avance rápido.
Otra forma, sin duda bastante bruta, es simplemente volver a crear la rama:
git fetch remote
git branch -f localbranch remote/remotebranch
Esto desecha la sucursal obsoleta local y recrea una con el mismo nombre, así que úsala con cuidado ...
Para muchos casos (como la fusión), puede usar la rama remota sin tener que actualizar la rama de seguimiento local. Agregar un mensaje en el reflog suena como una exageración y evitará que sea más rápido. Para facilitar la recuperación, agregue lo siguiente en su configuración de git
[core]
logallrefupdates=true
Entonces escribe
git reflog show mybranch
Para ver la historia reciente de tu sucursal.
Puede clonar el repositorio y hacer la fusión en el nuevo repositorio. En el mismo sistema de archivos, esto establecerá un enlace duro en lugar de copiar la mayoría de los datos. Termina tirando de los resultados en el repositorio original.
Solo puedes hacer esto si la combinación es un avance rápido. Si no es así, entonces git necesita que se revisen los archivos para que pueda combinarlos.
Para hacerlo solo para un avance rápido :
git fetch <branch that would be pulled for branchB>
git update-ref -m "merge <commit>: Fast forward" refs/heads/<branch> <commit>
donde <commit>
es el compromiso recuperado, el que desea avanzar rápidamente. Básicamente, es como usar git branch -f
para mover la rama, excepto que también lo registra en el reflog como si realmente hicieras la fusión.
Por favor, por favor, no haga esto por algo que no sea un avance rápido, o simplemente reiniciará su sucursal a la otra confirmación. (Para verificar, ver si git merge-base <branch> <commit>
da el SHA1 de la rama).