Rastree todas las ramas remotas de git como ramas locales

175

El seguimiento de una única rama remota como una rama local es lo suficientemente sencillo.

$ git checkout --track -b ${branch_name} origin/${branch_name}

Empujar todas las sucursales locales hacia el control remoto, crear nuevas sucursales remotas según sea necesario también es fácil.

$ git push --all origin

Quiero hacer lo contrario. Si tengo X número de ramas remotas en una sola fuente:

$ git branch -r 
branch1
branch2
branch3
.
.
.

¿Puedo crear ramas de seguimiento locales para todas esas ramas remotas sin necesidad de crearlas manualmente? Di algo como:

$ git checkout --track -b --all origin

He buscado en Google y RTM, pero hasta ahora he llegado a la litera.

Janson
fuente
3
Hay una forma aún más simple de rastrear una única sucursal remota como sucursal local:git checkout --track origin/branchname
Cerran
Esto no es exactamente lo que pediste, pero funciona para mí: obtén git completions: github.com/git/git/blob/master/contrib/completion/… . Luego escriba git pull origin y presione tab, para obtener una lista de ramas remotas. Luego continúa escribiendo y presiona return.
Max Heiber

Respuestas:

111

Usando bash:

después de git 1.9.1
for i in `git branch -a | grep remote | grep -v HEAD | grep -v master`; do git branch --track ${i#remotes/origin/} $i; done

créditos: Val Blant, Elias y Hugo

antes de git 1.9.1

Nota: el siguiente código si se usa en versiones posteriores de git (> v1.9.1) causa

  1. (error) Todas las ramas creadas para rastrear el maestro
  2. (molestia) Todos los nombres de sucursales locales creados con el prefijo origin/
for remote in `git branch -r `; do git branch --track $remote; done

Actualice las sucursales, suponiendo que no haya cambios en sus sucursales de seguimiento locales:

for remote in `git branch -r `; do git checkout $remote ; git pull; done

Ignora las advertencias ambiguas de cambio de nombre, git parece preferir la rama local como debería.

Otón
fuente
2
Gracias por el aviso sobre las advertencias de cambio de nombre. Eso fue útil.
Paul
1
Gracias Otto, sospeché que las secuencias de comandos serían la única solución. Has proporcionado una muy simple.
Janson
1
@ Jason ¿Sigue siendo hoy la única solución para crear scripts?
cregox
1
@Cawas: hasta tendrá que crear manualmente ramas de seguimiento, pero git pulltiene un --allinterruptor, que buscará + fusionará todas las ramas rastreadas.
naught101
13
Esto no funcionó para mí en Git 1.9.1. "git branch --track <banch_name>" crea una nueva rama <branch_name> que rastrea la rama local maestra, en lugar de la rama remota que queríamos. Entonces, este script creó un grupo de ramas locales que apuntaban al maestro local. Publicaré la solución a continuación.
Val Blant
183

La respuesta dada por Otto es buena, pero todas las ramas creadas tendrán "origen /" como inicio del nombre. Si solo desea que la última parte (después de la última /) sean sus nombres de rama resultantes, use esto:

for remote in `git branch -r | grep -v /HEAD`; do git checkout --track $remote ; done

También tiene el beneficio de no darle ninguna advertencia sobre referencias ambiguas.

tjmcewan
fuente
Git no agregará "origen" al nombre de la sucursal de seguimiento local.
Adam Dymitruk
14
@adymitruk: En realidad, se comporta exactamente como dije para mí en OSX 10.6.4, usando git 1.7.2.2 (la última versión estable de este comentario). Otto incluso menciona advertencias ambiguas de cambio de nombre: las advertencias no tendrían que existir si "origen /" no fuera parte del nombre de cada sucursal local. Aquí está la salida 'git branch' después de ejecutar el comando de Otto: [maestro, origen / CABEZA, origen / gráficos, origen / maestro, origen / producción, origen / puesta en escena]. Y mi comando: [gráficos, master, producción, puesta en escena].
tjmcewan
1
+ Editar: encontrado article.gmane.org/gmane.comp.version-control.git/112575 explicando por qué.
Philip Oakley
8
Estoy de acuerdo: esta es una solución mejor que la que actualmente es la respuesta "aceptada".
tobias.mcnulty
2
En lugar de grep -v master, ¿qué tal grep -v /HEAD? Esto parece filtrar la rama predeterminada, sin necesidad de personalización
dashrb
22

La mayoría de las respuestas aquí complican demasiado el análisis de la salida de git branch -r. Puede usar el siguiente forbucle para crear las ramas de seguimiento en todas las ramas del control remoto de esta manera.

Ejemplo

Digamos que tengo estas ramas remotas.

$ git branch -r
  origin/HEAD -> origin/master
  origin/development
  origin/integration
  origin/master
  origin/production
  origin/staging

Confirme que no estamos rastreando nada más que maestro, localmente:

$ git branch -l    # or using just git branch
* master

Puede usar este único revestimiento para crear las ramas de seguimiento:

$ for i in $(git branch -r | grep -vE "HEAD|master"); do 
    git branch --track ${i#*/} $i; done
Branch development set up to track remote branch development from origin.
Branch integration set up to track remote branch integration from origin.
Branch production set up to track remote branch production from origin.
Branch staging set up to track remote branch staging from origin.

Ahora confirme:

$ git branch
  development
  integration
* master
  production
  staging

Para eliminarlos:

$ git br -D production development integration staging 
Deleted branch production (was xxxxx).
Deleted branch development (was xxxxx).
Deleted branch integration (was xxxxx).
Deleted branch staging (was xxxxx).

Si utiliza el -vvinterruptor a git branchpuede confirmar:

$ git br -vv
  development xxxxx [origin/development] commit log msg ....
  integration xxxxx [origin/integration] commit log msg ....
* master      xxxxx [origin/master] commit log msg ....
  production  xxxxx [origin/production] commit log msg ....
  staging     xxxxx [origin/staging] commit log msg ....

Desglose de for loop

El ciclo básicamente llama al comando git branch -r, filtrando cualquier rama HEAD o maestra en la salida usando grep -vE "HEAD|master". Para obtener los nombres de solo las ramas menos la origin/subcadena, usamos la manipulación de cadenas de Bash ${var#stringtoremove}. Esto eliminará la cadena, "stringtoremove" de la variable $var. En nuestro caso, estamos eliminando la cadena origin/de la variable $i.

NOTA: Alternativamente, puede usar git checkout --track ...para hacer esto también:

$ for i in $(git branch -r | grep -vE "HEAD|master" | sed 's/^[ ]\+//'); do 
    git checkout --track $i; done

Pero no me importa particularmente este método, ya que lo está cambiando entre las ramas ya que realiza un pago. Cuando termine, te dejará en la última rama que creó.

Referencias

slm
fuente
1
Funciona perfectamente con git versión 2.3.2 (Apple Git-55)
AndrewD
22

Actualización de Q1 2020: Mohsen Abasi propone en los comentarios , basado en el 2014 slm 's respuesta , la alternativa más simple:

for i in $(git branch -r | grep -vE "HEAD|master" | sed 's/^[ ]\+//'); 

Y utiliza en $()lugar de retrocesos obsoletos .

Como mencioné en otra vieja respuesta , el uso git for-each-refes probablemente más rápido .
Y usaría el nuevo git switchcomando (Git 2.23+) , que reemplaza el confusogit checkout .

for i in $(git for-each-ref --format=%(refname:short) \
  --no-merged=origin/HEAD refs/remotes/origin); do \
    git switch --track $i; \
done

De esa manera, no es grepnecesario.


Antigua respuesta original (2011):

Aquí está mi one-liner que uso (en un shell bash, probado con msysgit1.7.4):

Para copiar y pegar:

remote=origin ; for brname in `git branch -r | grep $remote | grep -v master | grep -v HEAD | awk '{gsub(/^[^\/]+\//,"",$1); print $1}'`; do git branch --set-upstream-to $remote/$brname $brname; done

Para más legibilidad:

remote=origin ; // put here the name of the remote you want
for brname in `
    git branch -r | grep $remote | grep -v master | grep -v HEAD 
    | awk '{gsub(/^[^\/]+\//,"",$1); print $1}'
`; do 
    git branch --set-upstream-to $remote/$brname $brname; 
done
  • solo seleccionará ramas ascendentes del control remoto que especifique en la remotevariable (puede ser ' origin' o cualquier nombre que haya establecido para uno de los controles remotos de su repositorio Git actual).
  • extraerá el nombre de la rama: a origin/a/Branch/Name => a/Branch/Nametravés de la awkexpresión.
  • establecerá la rama ascendente a través de --set-upstream-to(o -u) , no --track:
    La ventaja es que, si la rama ya existe, no fallará y no cambiará el origen de esa rama, solo configurará la branch.xxx.(remote|merge)configuración.

    branch.aBranchName.remote=origin
    branch.aBranchName.merge=refs/heads/a/Branch/Name
    

Ese comando creará ramas locales para todas las ramas remotas ascendentes y establecerá su configuración remota y de fusión en esa rama remota.

VonC
fuente
55
Esto me da "fatal: la rama" lo que sea "no existe" para cada rama que existe solo en el control remoto y no tiene una rama local correspondiente.
Chris Dodd
Creo que si el nombre de una rama contiene / por ejemplo: feature / rc-41-bckend, ¡esta solución no funciona!
Mohsen Abasi
@VonC Basado en la respuesta de "slm": $ para i en $ (git branch -r | grep -vE "HEAD | master" | sed 's / ^ [] \ + //'); hacer git checkout - seguimiento $ i; hecho
Mohsen Abasi
@MohsenAbasi Se ve bien. En mi respuesta, mencioné usar en --set-upstream-tolugar de --tracksin embargo.
VonC
@MohsenAbasi He incluido su alternativa en la respuesta para mayor visibilidad. He agregado otra forma posible de enumerar ramas remotas y usar en git switchlugar de git checkout. Pero tu (muy buena) idea permanece.
VonC
14

Podrías escribir ese script con bastante facilidad, pero no sé cuándo sería valioso. Esas ramas se retrasarían rápidamente y tendrías que actualizarlas todo el tiempo.

Las sucursales remotas se mantendrán actualizadas automáticamente, por lo que es más fácil crear la sucursal local en el punto donde realmente desea trabajar en ella.

Dustin
fuente
2
Ese es un buen punto. El principal caso de uso en el que estoy pensando es configurar un entorno de desarrollo local basado en un repositorio de git remoto. Entonces, cuando hago mi clon inicial, también quiero rastrear todas las ramas remotas tal como están en ese momento.
Janson
1
El práctico git upactualiza todas las sucursales locales.
Hugo
para fusionar dos repositorios y eliminar el control remoto
endolith hace
9
for i in `git branch -a | grep remote`; do git branch --track ${i#remotes/origin/} $i; done
Val Blant
fuente
44
Tuve que agregar un | grep -v HEADa la tubería para que funcione correctamente.
Elias Dorneles
9

sin ninguna secuencia de comandos (en un directorio vacío):

$ git clone --bare repo_url .git
$ git config core.bare false
$ git checkout

después de eso, todas las ramas remotas se verán como locales.


original (en ruso) .

aleksandr barakin
fuente
Esta es la solución más simple por lejos y funcionó para mí en 2.21.0.windows.1
Rotsiser Mho
7

Si desea usar powershell y su control remoto se llama origen. Entonces esto funciona.

git fetch    
git branch -r  | %{$_ -replace "  origin/"} | %{git branch --track $_ "origin/$_"}
BigMiner
fuente
Esto fue súper útil, terminé usando una ligera variación para que funcione con mi git svn clone'drepositorio:git branch -r | %{$_ -replace " origin/"} | %{git checkout -b $_ "origin/$_"}
Nate
También hice una ligera variación porque mis sucursales locales ya existen:git branch -r | %{$_ -replace " origin/"} | %{git branch -u "origin/$_" $_}
ch271828n
3
for branch in `git branch -a | grep remotes | grep -v HEAD | grep -v master`; do  git branch --track ${branch##*/} $branch; done

Use esto y no tendrá advertencias como: refname 'origin / dev' es ambiguo

bruziuz
fuente
3

Aquí está mi solución del comando BASH que hace referencia a @tjmcewan:

for remote in `git branch -r | grep -v /HEAD `; do git branch --track ${remote/"origin/"/""}; done

Mi objetivo es resolver el problema de que todas las ramas creadas tendrán "origen /" como inicio del nombre, porque probé que las variables $ remotas todavía incluyen "origen /":

for remote in `git branch -r | grep -v /HEAD`; do echo $remote ; done
Nick Tsai
fuente
Después de probar BASH de @tjmcewan, descubrí que todos los nombres de las ramas rastreadas sin 'origin /' en local, no sé por qué.
Nick Tsai
1
El primer comando crea brances que rastrean "maestro". Eso no es lo que la mayoría de la gente puede desear.
Alexei Osipov
@AlexeiOsipov ¡Gracias!
Nick Tsai
2

Para hacer lo mismo que la respuesta de tjmcewan pero en Windows, llame a esto desde un archivo por lotes :

for /f "delims=" %%r in ('git branch -r ^| grep -v master') do git checkout --track %%r

O esto desde la línea de comando :

for /f "delims=" %r in ('git branch -r ^| grep -v master') do git checkout --track %r
Hugo
fuente
1

Desde git 2.23 en adelante:

for branch in `git branch -r | grep origin/`; do git switch -t -C ${branch#origin/} $branch; git pull; done

La -Cbandera de git switchcrea o restablece si ya existe.

documentación del interruptor git

AeroX
fuente
0

En caso de que ya tenga algunas sucursales desprotegidas y desee

  • mira todas las ramas restantes desde el control remoto
  • asegúrese de que todas las sucursales locales rastreen las sucursales remotas

puede usar el siguiente script compatible con bash y zsh:

git branch -r | while read b; do if git branch | grep -q " ${b##*/}$"; then git branch --set-upstream ${b##*/} $b; else git branch --track ${b##*/} $b; fi; done
simonair
fuente
0
for rembranch in `git remote update 2>&1 > /dev/null ; git branch -r|egrep -wv "HEAD|master"`
do 
    git checkout --track -b `echo $rembranch|awk -F\/ '{print $2}'` $rembranch; 
done

Explicación:

línea 1: 'git branch -r' (seguido de 'git remote update' para actualizar la información sobre los cambios a remote) enumera todas las ramas remotas; 'egrep -vw' se usa para eliminar entradas que tienen HEAD y master en el resultado.

línea 3: Rastree la rama remota nombrada mientras la extrae localmente. Se utiliza un awk simple para evitar que 'origin /' sea el sufijo de las sucursales locales.

ksvrgh
fuente
0

Usando bash, si quieres pagar todas las ramas:

for remote in `git branch -r`; do git checkout $(echo $remote | cut -d'/' -f 2); done

Es importante tener en cuenta que cuando realiza una búsqueda que derriba nuevas ramas de seguimiento remoto, no tiene automáticamente copias locales editables de ellas.

Jason Chen
fuente