Administrar muchos repositorios de git

85

Configurar un proyecto es fácil en git y, por lo tanto, puedo tener un repositorio separado incluso para un script pequeño. Ahora el problema es cómo gestionarlos.

Trabajo en varios lugares con estos repositorios. Cuando haya realizado cambios en algún repositorio, quiero poder actualizar los repositorios en otros lugares.

Así que tengo un directorio con muchos repositorios.

  1. ¿Cómo puedo buscarlos todos?
  2. ¿Cómo puedo comprobar si alguno de ellos tiene cambios sin confirmar?
  3. ¿Cómo puedo comprobar si alguno de ellos tiene cambios para fusionar?

Y sería bueno poder hacer esto con un solo comando.

La salida debe ser lo suficientemente silenciosa para notar realmente las cosas que se deben hacer.

iny
fuente
La misma pregunta se respondió a hg mercurial.
Serge Stroobandt

Respuestas:

44

Recomiendo encarecidamente la herramienta de repositorios múltiples mr . Solía ​​usar un script de shell personalizado según lo recomendado por otros durante algún tiempo, pero usar mr tiene los siguientes beneficios para mí:

  • Es genérico: se puede usar una combinación de varios sistemas de control de versiones, no solo git (por ejemplo, Mercurial, SVN, etc.).
  • Es rápido: mr puede ejecutar varios trabajos en paralelo. Utilizo varios repositorios git / mercurial y los sincronizo varias veces al día. Mr acelera tremendamente este proceso.
  • Es fácil y rápido administrar la lista de pagos del repositorio. Simplemente use 'mr register' en lugar de modificar la lista de proyectos en su script personalizado.

Con respecto a su pregunta sobre la salida silenciosa: el nivel de verbosidad se puede modificar usando el interruptor de línea de comando -q. Prefiero la salida predeterminada que parece unificar muy bien la salida en un resumen breve y claro.

Utilizo el siguiente alias para el comando mr para asegurarme de que mr siempre elija mi lista de proyectos predeterminada almacenada en $ HOME y use 5 subprocesos paralelos:

alias mr='mr -d ~/ -j 5 '
Sandro Giessl
fuente
5
¿Es compatible con Windows?
Fitzchak Yitzchaki
es genial pero no admite el etiquetado de git (a partir de 2016-08)
Hugo Zaragoza
@CADbloke no menciona Windows en la página de instalación, pero como script de Perl podría / debería / podría funcionar en Windows.
scipilot
2
@HugoZaragoza, siempre puedes definir este comando tú mismo [DEFAULT] tag = git tag "$ @"
AlexS
2
alias pa='find . -name .git -print -execdir git pull \;'entonces, paes suficiente
DawnSong
19

Debo decir que comencé con la respuesta actualmente aceptada (solo un montón de scripts de ayuda que iteran sobre los repositorios), pero en general, fue una experiencia deficiente para mí.

Entonces, después de probar mr, repo y git-submodules, encontré que cada uno carecía de una manera diferente, así que terminé haciendo mi propia variante: http://fabioz.github.io/mu-repo, que es una herramienta madura en este punto, tiene flujos de trabajo que le permiten:

  • clonar varios repositorios
  • diff (y editar) cambios actuales en múltiples repositorios
  • vista previa de los cambios entrantes
  • ejecutar comandos en múltiples repositorios en paralelo
  • crear grupos de repositorios
  • ejecutar comandos no relacionados con git en múltiples repositorios
  • etc (consulte la página de inicio para obtener más información).

Tenga en cuenta que es compatible con cualquier sistema operativo donde se ejecute Python;)

Fabio Zadrozny
fuente
Su respuesta sugiere que mu-repo es mejor que lo que hace mr. Pero mu-repo no admite repositorios no git.
Shaunak Sontakke
1
Entonces, su propósito es realmente admitir solo repositorios de git (que es lo que hizo la pregunta); aunque también puede hacer mu sh <some command>para ejecutar algún comando arbitrario en múltiples repositorios, su finalidad es tratar con git y no con otros sistemas de control de versiones. .si lo necesita, entonces sí, utilice una herramienta diferente.
Fabio Zadrozny
14

gr (git-run) extiendela funcionalidad de mr (solo paragit). Me resulta más fácil organizar varios repositorios de git usando su sistema de etiquetas. Singrembargo, elcódigo deno está bien mantenido. Si está usando bash, asegúrese de usarlo con elformulario en-t taglugar de#tag.

Memming
fuente
Parece que el desarrollo se ha recuperado un poco desde entonces: github.com/mixu/gr/graphs/contributors
Dave Forgac
8

Puede intentar usar el repositorio con un manifest.xmlarchivo personalizado para especificar dónde están sus repositorios. Existe alguna documentación sobre cómo hacer esto.

Alternativamente, puede usar git-submodule(1) .

Spoike
fuente
2
git-submodule sería bueno si quisiera mantener los repositorios exactamente en el mismo estado, pero ese no es el caso. El conjunto de repositorios no es el mismo en todos los lugares. Podría haber cambios no comprometidos. Podría haber cambios que aún no quiero fusionar.
iny
No sabía nada de git-submodule. Gracias por mencionarlo.
sykora
La documentación para el repositorio es bastante mínima y parece que está destinada a los diferentes tipos de flujo de trabajo que quiero usar.
iny
6

Escribí una herramienta llamada " RepoZ " que descubre automáticamente los repositorios de git tan pronto como los clonas o cambias algo en ellos, como cambiar una rama, por ejemplo.

Una vez encontrados, los repositorios son "rastreados". Eso simplemente los mostrará en una lista de repositorios locales que incluyen una densa información de estado inspirada en posh-git . Esto contiene la rama actual y más cosas como ediciones de archivos y el recuento de confirmaciones entrantes o salientes.

Interfaz de usuario de RepoZ

Esto ayuda a realizar un seguimiento de sus repositorios locales y el trabajo inconcluso para confirmar o impulsar. Además, puede utilizar la lista de repositorios como navegación para cambiar de un repositorio a otro.

Navegación RepoZ

"¿Cómo puedo ir a buscarlos a todos?"

La versión para Windows ofrece un menú contextual para buscar o extraer un repositorio. Con la selección múltiple, puede ejecutar acciones en varios repositorios a la vez.

Sin embargo, puede encontrar otra función muy útil:

RepoZ Auto-Fetch

Con Auto fetch, puede decirle a RepoZ que busque los controles remotos de todos sus repositorios de git periódicamente en segundo plano. Estas recuperaciones no colisionarán con tus confirmaciones locales, por supuesto. No hay intentos de fusión locales como con git pull.

Waescher
fuente
Sí, muy mal y no merecido. Abierto para RP en cualquier momento. Hazme ping.
Waescher
5

gitslave es una herramienta que puede ejecutar el mismo comando en muchos repositorios creando una relación superproyecto / subproyecto entre el super y los subs. Esto (por defecto) proporciona un resumen de salida para que pueda concentrarse en los repositorios que proporcionan una salida única (útil para git status, no tan útil para git ls-files).

Esto se usa generalmente para proyectos en los que necesita ensamblar varios repositorios juntos y mantenerlos en la misma rama o etiqueta al mismo tiempo o lo que sea. Para mi directorio de repositorios (desnudos), solo tengo un pequeño archivo MAKE que me permite ejecutar comandos git arbitrarios, que, como puede ver, utilizo principalmente para fsck y gc:

full: fsck-full gc-aggressive
        @:

fsck-full:
        for f in */.; do (cd $$f; echo $$f; git fsck --full || echo $$f FAILED); done

gc-aggressive:
        for f in */.; do (cd $$f; echo $$f; git gc --aggressive || echo $$f FAILED); done

%:
        for f in */.; do (cd $$f; git $@ || echo $$f FAILED); done
Seth Robertson
fuente
5

He creado un alias y una función para ejecutar cualquier comando git en todos los repositorios disponibles en un directorio (de forma recursiva). Puedes encontrarlo aquí: https://github.com/jaguililla/dotfiles/git

Este es el código:

#!/bin/sh
# To use it: source git_aliases

# Example: rgita remote \;
alias rgita='find . -type d -name .git -execdir git'

# Example: rgit remote -vv
rgit() {
  rgita "$@" \;
}

Espero eso ayude :)

jaguililla
fuente
1
delgado y útil!
Kevin Chou
¡Fantástico! Simple de una sola línea para poner en .bash_aliases: alias rgit='function _rgit(){ find . -type d -name .git -printf "\n%p\n" -execdir git "$@" \;; }; _rgit'. Orínelo, luego p rgit status. Ej . Llame .
Ford04
4

Puede usar la git-status-allgema para esto: https://github.com/reednj/git-status-all

# install the gem    
gem install git-status-all

# use the status-all subcommand to scan the directory
git status-all

También hay una opción de recuperación que buscará desde el origen para todos los repositorios antes de mostrar el estado:

git status-all --fetch

estado de git todo

Nathan
fuente
1
Muy buen enfoque. A diferencia de la mayoría de las herramientas más votadas, no es necesario registrar primero los repositorios, sino que simplemente verifica todos los subdirectorios.
luator
find . -name .git -print -execdir git status \;está bien
DawnSong
3

Utilizo este script para ejecutar fácilmente comandos git en todos mis repositorios.

#!/bin/sh
if [ ! "$1" = "" ] ; then

   if [ "$GITREPO" = "" -a -d "$HOME/cm/src" ] ; then
      GITREPO="$HOME/cm/src"
   fi

   if [ "$GITREPO" != "" ] ; then

      echo "Git repositories found in $GITREPO"
      echo "-=-=-=-=-=-=-=-=-=-=-=-=-=-"

      DIRS="`/bin/ls -1 $GITREPO`"

      for dir in $DIRS ; do

         if [ -d $GITREPO/$dir/.git ] ; then
            echo "$dir -> git $1"
            cd $GITREPO/$dir ; git $@
            echo
         fi

      done
   else

      echo "Git repositories not found."

   fi
fi

De forma predeterminada, el script buscará repositorios de git en ~ / cm / src, pero puede anular esto configurando la variable de entorno GITREPO a su gusto.

Este script se basa en este script .

Scotts
fuente
find . -name .git -print -execdir git pull \;hace lo que piensa.
DawnSong
3

Escribí una herramienta de línea de comandos llamada gita para administrar múltiples repositorios. Muestra el estado de los repositorios registrados uno al lado del otro, por ejemplo

ingrese la descripción de la imagen aquí

También puede delegar comandos / alias de git desde cualquier directorio de trabajo.

Ahora para responder a sus preguntas usando esta herramienta:

¿Cómo puedo buscarlos todos?

gita fetch

¿Cómo puedo comprobar si alguno de ellos tiene cambios sin confirmar?

El gita lscomando muestra 3 símbolos posibles junto al nombre de la rama, que indica

  • +: cambios por etapas
  • *: cambios sin etapas
  • _: archivos / carpetas sin seguimiento

¿Cómo puedo comprobar si alguno de ellos tiene cambios para fusionar?

Los nombres de las ramas están coloreados de 5 formas

  • blanco: la sucursal local no tiene sucursal remota
  • verde: la rama local es la misma que la rama remota
  • rojo: la sucursal local se ha separado de la sucursal remota
  • púrpura: la sucursal local está por delante de la sucursal remota (buena para empujar)
  • amarillo: la rama local está detrás de la rama remota (buena para la fusión)

Para instalarlo, simplemente ejecute

pip3 install -U gita
nos
fuente
2

Si alguien todavía está mirando este hilo, consulte mi script de shell llamado gitme

Deberá ingresar manualmente sus repositorios de git locales, pero yo uso esta herramienta todos los días para colaborar en múltiples proyectos de git en múltiples computadoras.

Tu puedes correr git clone https://github.com/robbenz/gitme.git

también el guión se publica a continuación

#!/bin/bash -e

REPOS=( 
/Users/you/gitrepo1
/Users/you/gitrepo2
/Users/you/gitrepo3
/Users/you/gitrepo4
)

MOVE="Moving to next REPO... \n" 

tput setaf 2;echo "What ya wanna do? You can say push, pull, commit, ftp push, or status"; tput sgr0

read input

if [ $input =  "commit" ]
then
    tput setaf 2;echo "Do you want a unique commit message? [y/n]";tput sgr0
    read ans
    if [ $ans = "y" ]
    then 
        for i in "${REPOS[@]}"
        do
            cd "$i"
            tput setaf 6;pwd;tput sgr0 
            git add . -A
            read -p "Commit description: " desc  
            git commit -m "$desc"
            tput setaf 2;echo  $MOVE;tput sgr0 
            sleep 1
        done 
    else 
        for i in "${REPOS[@]}"
        do
            cd "$i"
            tput setaf 6;pwd;tput sgr0 
            git add . -A
            git commit -m "autocommit backup point"
            tput setaf 2;echo  $MOVE;tput sgr0 
            sleep 1
        done
    fi 
elif [ $input = "push" ] || [ $input = "pull" ] || [ $input = "ftp push" ] || [ $input = "status" ]
    then
        for i in "${REPOS[@]}"
do
    cd "$i"
    tput setaf 6;pwd;tput sgr0 
    git $input 
    tput setaf 2;echo  $MOVE;tput sgr0 
    sleep 1
    done 
else tput setaf 1;echo "You have zero friends";tput sgr0 
fi

Configuré un alias en mi ~ / .bash_profile para alias gitme='sh /path/to/gitme.sh'

RobBenz
fuente
1

Deberías revisar rgit en el CPAN que ejecuta recursivamente comandos git en todos los repositorios en un árbol de directorios.

De los documentos:

Esta utilidad busca de forma recursiva en un directorio raíz (que puede ser el directorio de trabajo actual o, si se ha configurado, el directorio proporcionado por la variable de entorno GIT_DIR) para todos los repositorios de git, ordene esta lista por la ruta del repositorio, chdir en cada uno de ellos, y ejecuta el comando git especificado.

Brian Phillips
fuente
1

¡Acabo de crear una herramienta que hace lo que quieres!

  1. ¿Cómo puedo buscarlos todos? gmaster fetch
  2. ¿Cómo puedo comprobar si alguno de ellos tiene cambios sin confirmar? gmaster status
  3. ¿Cómo puedo comprobar si alguno de ellos tiene cambios para fusionar? gmaster status

Se llama gitmaster: https://github.com/francoiscabrol/gitmaster

francoiscabrol
fuente
1

Escribí esta función bash simple en mi .bash_profile para poder ejecutar git, maven, gradle o cualquier otro comando bash solo en todos los repositorios de git:

# usefull function to work with multiple git repositories
all() {
    failed=0
    printf '>>> START RUNNING: "%s" >>>' "$*"
    for d in */; do
        pushd "$d" > /dev/null
        if [ -d ".git" ]
        then
            printf '\n--------------------------------------------\n\n'
            pwd
            eval $@
            if [ $? -ne 0 ]
            then
                failed=1
                break;
            fi
        fi
        popd > /dev/null
    done
    if [ $failed -eq 0 ]
    then
        printf '\n--------------------------------------------\n'
        printf '<<< RAN "%s" WITH SUCCESS!!! <<<' "$*"
    else
        printf '\n<<< FAILED!!! <<<'
    fi
}

Esto se puede usar de esta manera

all git st
all git pull
all ./gradlew clean test
etc.
ChaudDolor
fuente
también se pueden ejecutar todos en paralelo usando: all './gradlew clean test &'
ChaudPain
0

Descargo de responsabilidad: estoy trabajando en esta herramienta en www.repoflow.com

¿Cómo puedo buscarlos todos?
¿Cómo puedo comprobar si alguno de ellos tiene cambios para fusionar?

  • Puede recuperar todos los repositorios involucrados (o empujarlos / extraerlos / confirmarlos), después de la recuperación, la interfaz de usuario se actualizará con el nuevo estado del repositorio, si el repositorio es divergente, puede ver el tipo de conflictos y comenzar a fusionarlos.

ingrese la descripción de la imagen aquí

¿Cómo puedo comprobar si alguno de ellos tiene cambios sin confirmar?

  • En la interfaz de usuario puede ver el estado de los archivos para cada repositorio (puede agregarlos / eliminarlos individualmente o en forma masiva).

ingrese la descripción de la imagen aquí

Estoy trabajando en esto, pero esto también está resolviendo las preguntas de OP y ayuda a administrar múltiples repositorios en general, puede usar la IU o la API GraphQL subyacente para crear sus propios scripts, considérelo como otra opción.

Víctor Jiménez
fuente
0

Hay una herramienta útil para buscar todos los repositorios múltiples. git-pull-alles una herramienta de línea de comandos para ejecutar en múltiples repositorios de git de forma asincrónica.

Instalación

npm install -g git-pull-all

Uso

Suponga que tiene estos archivos y directorios:

~/Projects/
  cool-examples/
    .git/
  funny-movies/
  my-todos.txt
  super-express/
    .git/

Cuando ejecuta el git-pull-allcomando en el ~/Projectsdirectorio, debe encontrar repositorios git secundarios (en el caso anterior, cool-examples y super-express ) y luego ejecutar git pullen cada uno de ellos.

$ cd ~/Projects
$ git-pull-all
funny-movies/
Not a git repository
cool-examples/
Already up-to-date.
super-express/
Already up-to-date.
Done!
git-pull-all ~/Projects

Enlace de GitHub: https://github.com/tatsuyaoiw/git-pull-all

Alper Ebicoglu
fuente
0

Yo uso el código de Visual Studio. Tenemos alrededor de 20 bibliotecas en nuestra base de código que son repositorios de Git separados, y la pestaña de control de fuente en Visual Studio Code es bastante buena para ver una vista "de un vistazo" de qué tan retrasados ​​o adelantados están los repositorios locales. También hay configuraciones para buscar periódicamente para mantener esa información actualizada, así como un botón de actualización.

No es tan conveniente como un script, pero cuando se trata de control de código fuente, me gusta ser el que hace los cambios. Se necesita un script muy bien escrito para tener cuidado de no sobrescribir los cambios, etc. Con el enfoque de VS Code, obtienes una buena cantidad de información rápidamente que puedes actuar por ti mismo.

Aquí hay una captura de pantalla de cómo se ve:

Ventana de control de fuente en VS Code

Ty Deuty
fuente
0

Encontré una gran solución para extraer de la rama actual de todos los subdirectorios que tienen una carpeta .git, incluso si cada repositorio tiene una rama diferente. El comando es de una sola línea, lo suficientemente flexible como para modificarlo para diferentes comandos de git y puede tener un alias.

Simplemente copie y pegue lo siguiente:

find . -type d -maxdepth 2 -name .git -exec sh -c 'cd $0 && cd .. && git pull origin $(git rev-parse --abbrev-ref HEAD)' {} \;

Desglosando:

find . -type d -maxdepth 2 -name .git 

Busque todos los directorios (-tipo d) en el directorio actual (find.) Que tengan el nombre ".git" (-name .git), buscando un máximo de dos directorios de profundidad (2 en lugar de 1 porque estamos buscando el git dentro de la carpeta git repo).

-exec sh -c 

Ejecute el siguiente comando de shell (exec sh -c)

'cd $0 && cd .. && git pull origin $(git rev-parse --abbrev-ref HEAD)'

Cambie el directorio al primer argumento (cd $ 0), luego cambie el directorio un nivel hacia arriba para dejar la carpeta .git (cd ..) luego haga git pull origin mientras especifica la rama ejecutando git rev-parse ... para la rama actual HEAD cometer.

{} \;

El "{}" es la ruta relativa de resultado que obtenemos del hallazgo inicial comando de . Los ; se utiliza para finalizar el comando.

Probado en MacOS 10.14.6 en zsh. Tal como está, funciona solo cuando las sucursales remotas y locales tienen el mismo nombre, AFAIK.

Puede modificar esto para obtener el estado. Espero que pueda agregar argumentos para hacer esto más flexible, pero aún no lo he intentado.

Ahmed Tawfik
fuente
-1

https://github.com/wwjamieson3/envisionTools tiene un script bash llamado gitstat que hace esto y mucho más. Es compatible con GNU y mac. Puede realizar búsquedas desde controles remotos si se le solicita. Muestra archivos sin seguimiento, modificados, agregados, eliminados y organizados. Se diferencia con los controles remotos al mostrar confirmaciones no fusionadas en controles remotos y confirmaciones locales no presionadas. También puede mostrar resultados codificados por colores en modo resumen o detallado e incluso HTML. Utiliza localizar en lugar de buscar porque es infinitamente más rápido e incluso le pedirá que actualice su base de datos de localización si se está volviendo demasiado antigua.

William Jamieson
fuente
2
¡Gracias por publicar tu respuesta! Asegúrese de leer detenidamente las preguntas frecuentes sobre la autopromoción. También tenga en cuenta que es necesario que publique un descargo de responsabilidad cada vez que enlace a su propio sitio / producto.
Andrew Barber
3
Desafortunadamente, el enlace github wwjamieson3 / envisionTools está roto.
Brenda J. Butler
@williamJamieson ¿EnvisionTools es un repositorio privado de GitHub?
eebbesen
-5

Parece que escribir un guión para hacerlo es bastante fácil. Esencialmente, necesita iterar sobre los repositorios y luego usar comandos como git ls-files, git diff y git log.

iny
fuente
Sé que es tarde, pero ¿podrías publicar el guión?
l0b0
No hay "el guión". Estoy usando un script que escribí para mis propias necesidades, pero no es genérico.
iny
"git diff" es realmente complicado si desea obtener un único archivo diff que se pueda revertir y volver a aplicar con un solo comando de parche.
proski
4
Literalmente, cualquiera de las respuestas debería ser la respuesta aceptada, pero esto.
Kennet Celeste