Gerenciando muitos repositórios git


87

Configurar um projeto é fácil no git e, portanto, posso ter um repositório separado, mesmo para pequenos scripts. Agora o problema é como gerenciá-los.

Eu trabalho em vários lugares com esses repositórios. Quando eu tiver feito alterações em algum repositório, quero ser capaz de atualizar os repositórios em outros lugares.

Portanto, tenho um diretório com muitos repositórios nele.

  1. Como posso obter todos eles?
  2. Como posso verificar se algum deles tem alterações não confirmadas?
  3. Como posso verificar se algum deles tem alterações a serem mescladas?

E seria bom poder fazer isso com um comando.

A saída precisa ser silenciosa o suficiente para realmente notar o que fazer.


A mesma pergunta respondida por hg mercurial.
Serge Stroobandt

Eu uso o recurso de seleção de vários cursores / edição de várias linhas do meu editor de código (código VS) para criar script em lote / shell e executá-lo de uma vez. Com esta solução simples e estúpida, eu sei o que estou fazendo e o que posso esperar da execução desses comandos. Sem adivinhação, sem aprendizagem, sem necessidade de personalização. Outro motivo é que sempre que desejo executar comandos em conjuntos diferentes de repositórios que residem em um diretório pai comum.
IsmailS

Respostas:


45

Eu recomendo fortemente a ferramenta de múltiplos repositórios mr . Eu costumava usar um script de shell personalizado, conforme recomendado por outros há algum tempo, mas usar o mr tem os seguintes benefícios para mim:

  • É genérico: uma conjunção de vários sistemas de controle de versão pode ser usada, não apenas git (por exemplo, Mercurial, SVN, etc.).
  • É rápido: o mr pode executar vários trabalhos em paralelo. Eu uso vários repositórios git / mercurial e os sincronizo várias vezes ao dia. O Sr. acelera tremendamente esse processo.
  • É fácil e rápido gerenciar a lista de checkouts do repositório. Basta usar 'mr register' em vez de modificar a lista de projetos em seu script personalizado.

Com relação à sua pergunta sobre a saída silenciosa: O nível de detalhamento pode ser modificado usando a opção de linha de comando -q. Eu prefiro a saída padrão, que parece unificar bem a saída em um resumo curto e claro.

Eu uso o seguinte alias para o comando mr para garantir que mr sempre pegue minha lista de projetos padrão armazenada em $ HOME e use 5 threads paralelos:

alias mr='mr -d ~/ -j 5 '

é ótimo, mas não é compatível com git tagging (em 2016-08)
Hugo Zaragoza

@CADbloke não menciona janelas na página de instalação, mas como um script Perl pode / deveria / poderia funcionar em janelas.
scipilot de

2
@HugoZaragoza, você sempre pode definir este comando por si mesmo [DEFAULT] tag = git tag "$ @"
AlexS

2
alias pa='find . -name .git -print -execdir git pull \;'então, paé o suficiente
DawnSong

19

Devo dizer que comecei com a resposta atualmente aceita (apenas um monte de scripts de helpers que iteram nos repositórios), mas, de modo geral, foi uma experiência que faltou para mim.

Então, depois de tentar submódulos mr, repo e git, descobri que cada um faltava de uma maneira diferente, então, acabei fazendo minha própria variante: http://fabioz.github.io/mu-repo que é uma ferramenta madura em este ponto - tem fluxos de trabalho que permitem a você:

  • clonar repositórios múltiplos
  • diff (e editar) alterações atuais em repositórios múltiplos
  • visualizar as mudanças recebidas
  • execute comandos em vários repositórios em paralelo
  • criar grupos de repositórios
  • execute comandos não relacionados ao git em vários repositórios
  • etc (veja a página inicial para mais informações).

Observe que ele é compatível com qualquer sistema operacional em que Python seja executado;


Sua resposta sugere que o mu-repo é melhor do que o que o sr. Mas mu-repo não suporta repositórios não git.
Shaunak Sontakke

1
Bem, seu propósito é realmente oferecer suporte apenas a repositórios git (que é o que a pergunta feita) - embora você também possa mu sh <some command>executar alguns comandos arbitrários em repositórios múltiplos, toda a sua finalidade é lidar com git e não com outros sistemas de controle de versão. .se precisar disso, então sim, use uma ferramenta diferente.
Fabio Zadrozny

14

gr (git-run) estendea funcionalidade de mr (somente paragit). Acho mais fácil organizar vários repositórios git usando seu sistema de tag. O código paragrnão é bem mantido. Se você estiver usando o bash, certifique-se de usá-lo com o em-t tagvez do#tagformulário.


Parece que o desenvolvimento recuperou um pouco desde então: github.com/mixu/gr/graphs/contributors
Dave Forgac

8

Você pode tentar usar o repo com um manifest.xmlarquivo personalizado para especificar onde estão seus repositórios. Existe alguma documentação sobre como fazer isso.

Alternativamente, você pode usar git-submodule(1) .


2
git-submodule seria bom, se eu quisesse manter os repositórios exatamente no mesmo estado, mas não é o caso. O conjunto de repositórios não é o mesmo em cada local. Pode haver mudanças não confirmadas. Pode haver alterações que ainda não desejo mesclar.
iny

Eu não sabia sobre git-submodule. Obrigado por mencionar isso.
Sykora

A documentação do repo é mínima e parece que se destina a diferentes tipos de fluxo de trabalho que desejo usar.
iny

6

Eu escrevi uma ferramenta chamada " RepoZ " que descobre automaticamente os repositórios git assim que você os clona ou altera qualquer coisa neles, como trocar um branch, por exemplo.

Uma vez encontrados, os repositórios são "rastreados". Isso simplesmente os mostrará em uma lista de repositórios locais, incluindo uma densa informação de status inspirada no posh-git . Ele contém o branch atual e outras coisas como edições de arquivo e a contagem de commits de entrada ou saída.

IU RepoZ

Isso ajuda a manter o controle de seus repositórios locais e trabalho inacabado para confirmar ou enviar. Além disso, você pode usar a lista de repositórios como navegação para alternar de um repositório para outro.

Navegação RepoZ

"Como posso buscar todos eles?"

A versão para Windows oferece um menu de contexto para buscar ou puxar um repositório. Com a seleção múltipla, você pode executar ações em vários repositórios de uma vez.

No entanto, você pode achar outro recurso muito útil:

RepoZ Auto-Fetch

Com a busca automática, você pode dizer ao RepoZ para buscar os remotos de todos os seus repositórios git periodicamente em segundo plano. Essas buscas não irão colidir com seus commits locais, é claro. Não há tentativas de mesclagem local como com git pull.


Sim, muito ruim e não merecido. Aberto para RP a qualquer momento. Ping me.
Waescher

5

gitslave é uma ferramenta que pode executar o mesmo comando em muitos repositórios, criando uma relação superprojeto / subprojeto entre o super e os subs. Isso (por padrão) fornece um resumo de saída para que você possa se concentrar nos repositórios que fornecem uma saída única (útil para o status git, não tão útil para os arquivos-ls git).

Isso normalmente é usado para projetos em que você precisa montar vários repositórios juntos e mantê-los no mesmo branch ou tag ao mesmo tempo ou o que for. Para meu diretório de repositórios (vazios), só tenho um pequeno makefile que me permite executar comandos git arbitrários, que, como você pode ver, uso principalmente para fsck e 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

5

Fiz um alias e uma função para executar qualquer comando git em todos os repositórios disponíveis em um diretório (recursivamente). Você pode encontrá-lo aqui: https://github.com/jaguililla/dotfiles/git

Este é o 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 que ajude :)


1
fino e útil!
Kevin Chou

Fantatstic! One-liner simples de colocar em .bash_aliases: alias rgit='function _rgit(){ find . -type d -name .git -printf "\n%p\n" -execdir git "$@" \;; }; _rgit'. Fonte-o, por exemplo, ligue rgit status.
ford04 de

4

Você pode usar a git-status-allgema para isso: 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

Também há uma opção de busca que buscará na origem para todos os repositórios antes de exibir o status:

git status-all --fetch

git status all


1
Abordagem muito boa. Em contraste com a maioria das ferramentas mais votadas, não há necessidade de primeiro registrar os repositórios, em vez disso, ele simplesmente verifica todos os subdiretórios.
luator

find . -name .git -print -execdir git status \;está OK
DawnSong

3

Eu uso este script para executar comandos git facilmente em todos os meus repositórios.

#!/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

Por padrão, o script procurará por repositórios git em ~ / cm / src, mas você pode sobrescrever isso configurando a variável de ambiente GITREPO de sua preferência.

Este script é baseado neste script .


find . -name .git -print -execdir git pull \;faz o que você pensa.
DawnSong

3

Eu escrevi uma ferramenta de linha de comando chamada gita para gerenciar vários repositórios. Mostra o status dos repositórios registrados lado a lado, por exemplo

insira a descrição da imagem aqui

Ele também pode delegar comandos / aliases git de qualquer diretório de trabalho.

Agora, para responder às suas perguntas usando esta ferramenta:

Como posso obter todos eles?

gita fetch

Como posso verificar se algum deles tem alterações não confirmadas?

O gita lscomando mostra 3 símbolos possíveis ao lado do nome do ramo, o que indica

  • +: mudanças encenadas
  • *: mudanças não planejadas
  • _: arquivos / pastas não rastreados

Como posso verificar se algum deles tem alterações a serem mescladas?

Os nomes dos ramos são coloridos de 5 maneiras

  • branco: filial local não possui filial remota
  • verde: filial local é o mesmo que filial remota
  • vermelho: filial local divergiu da filial remota
  • roxo: o branch local está à frente do branch remoto (bom para push)
  • amarelo: o branch local está atrás do branch remoto (bom para fusão)

Para instalá-lo, basta executar

pip3 install -U gita

2

Se alguém ainda está olhando para este tópico, verifique meu script de shell chamado gitme

você precisará inserir manualmente seus repositórios git locais, mas eu uso essa ferramenta todos os dias para colaborar com vários projetos git em vários computadores.

você pode correr git clone https://github.com/robbenz/gitme.git

também o script é postado abaixo

#!/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

Eu configurei um alias no meu ~ / .bash_profile para alias gitme='sh /path/to/gitme.sh'


1

Você deve verificar o rgit no CPAN, que executa recursivamente comandos git em todos os repositórios em uma árvore de diretório.

Dos documentos:

Este utilitário procura recursivamente em um diretório raiz (que pode ser o diretório de trabalho atual ou - se tiver sido definido - o diretório fornecido pela variável de ambiente GIT_DIR) para todos os repositórios git, classifique esta lista pelo caminho do repositório, chdir em cada um eles e executa o comando git especificado.


1

Acabei de criar uma ferramenta que faz o que você quiser!

  1. Como posso obter todos eles? gmaster fetch
  2. Como posso verificar se algum deles tem alterações não confirmadas? gmaster status
  3. Como posso verificar se algum deles tem alterações a serem mescladas? gmaster status

Chama-se gitmaster: https://github.com/francoiscabrol/gitmaster


1

Escrevi esta função bash simples em meu .bash_profile para poder executar git, maven, gradle ou qualquer outro comando bash apenas em todos os repositórios 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
}

Isso pode ser usado desta forma

all git st
all git pull
all ./gradlew clean test
etc.

também era possível executá-los em paralelo usando: all './gradlew clean test &'
ChaudPain

0

Isenção de responsabilidade: estou trabalhando nesta ferramenta em www.repoflow.com

Como posso obter todos eles?
Como posso verificar se algum deles tem alterações a serem mescladas?

  • Você pode buscar todos os repositórios envolvidos (ou enviar / puxar / confirmá-los), após a busca, a IU será atualizada com o novo estado do repositório, se o repositório estiver divergido, você pode ver o tipo de conflitos e começar a mesclá-los.

insira a descrição da imagem aqui

Como posso verificar se algum deles tem alterações não confirmadas?

  • Na IU, você pode ver o estado dos arquivos de cada repositório (você pode adicioná-los / removê-los individualmente ou em massa).

insira a descrição da imagem aqui

Estou trabalhando nisso, mas também resolvendo as questões de OP e ajudando a gerenciar vários repositórios em geral. Você pode usar a IU ou a API GraphQL subjacente para criar seus próprios scripts, considere-o como outra opção.


0

Existe uma ferramenta útil para buscar todos os repositórios múltiplos. git-pull-allé uma ferramenta de linha de comando para executar em vários repositórios git de forma assíncrona.

Instalação

npm install -g git-pull-all

Uso

Suponha que você tenha estes arquivos e diretórios:

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

Quando você executa o git-pull-allcomando no ~/Projectsdiretório, ele deve encontrar repositórios git filhos (no caso acima cool-examples e super-express ) e depois executar git pullem cada um deles.

$ 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

Link do GitHub: https://github.com/tatsuyaoiw/git-pull-all


0

Eu uso o código do Visual Studio. Temos cerca de 20 bibliotecas em nossa base de código que são todos repositórios Git separados, e a guia de controle de origem no Visual Studio Code é muito boa para ver uma visão "rápida" de quão atrasados ​​ou adiantados os repositórios locais estão. Existem também configurações para buscar periodicamente para manter essas informações atualizadas, bem como um botão de atualização.

Não é tão conveniente quanto um script, mas quando se trata de controle de origem para mim, gosto de fazer as alterações. É necessário um script muito bem escrito para ter cuidado para não sobrescrever as alterações, etc. Com a abordagem do VS Code, você obtém uma boa quantidade de informações rapidamente para que possa agir por conta própria.

Aqui está uma captura de tela de sua aparência:

Janela de controle de fonte no VS Code


0

Eu encontrei uma ótima solução para extrair do branch atual de todos os subdiretórios que têm uma pasta .git, mesmo se cada repositório tiver um branch diferente verificado. O comando é de uma linha, flexível o suficiente para ser modificado para diferentes comandos git e pode ter um alias.

Basta copiar e colar o seguinte:

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

Dividindo:

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

Encontre todos os diretórios (-type d) no diretório atual (find.) Que têm o nome ".git" (-name .git), procurando no máximo dois diretórios de profundidade (2 em vez de 1 porque estamos procurando o pasta git dentro da pasta repo git).

-exec sh -c 

Execute o seguinte comando shell (exec sh -c)

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

Mude o diretório para o primeiro argumento (cd $ 0), então mude o diretório um nível acima para deixar a pasta .git (cd ..) então faça git pull origin enquanto especifica o branch executando git rev-parse ... para o branch atual Confirmar HEAD.

{} \;

O "{}" é o caminho relativo do resultado que obtemos do comando find inicial . O ; é usado para encerrar o comando.

Testado em MacOS 10.14.6 em zsh. No estado em que se encontra, funciona apenas quando as filiais remotas e locais têm o mesmo nome, AFAIK.

Você pode modificar isso para obter o status. Espero que você possa adicionar argumentos para tornar isso mais flexível, mas ainda não tentei.


0

Eu uso o recurso de seleção de vários cursores / edição de várias linhas do meu editor de código (código VS) para criar script em lote / shell e executá-lo de uma vez. Com esta solução simples e estúpida, eu sei o que estou fazendo e o que posso esperar da execução desses comandos. Sem adivinhação, sem aprendizagem, sem necessidade de personalização. Outro motivo é que sempre que desejo executar comandos em conjuntos diferentes de repositórios que residem em um diretório pai comum.


-1

https://github.com/wwjamieson3/envisionTools tem um script bash chamado gitstat que faz isso e muito mais. É compatível com GNU e mac. Ele pode realizar buscas de controles remotos, se solicitado. Mostra arquivos não rastreados, modificados, adicionados, excluídos e testados. Ele se diferencia dos remotos ao mostrar commits não mesclados em remotos e commits locais não enviados. Ele também pode exibir resultados codificados por cores em modo resumido ou detalhado e até mesmo HTML. Ele usa localizar em vez de localizar porque é infinitamente mais rápido e até solicitará a atualização do banco de dados de localização se estiver ficando muito antigo.


2
Obrigado por postar sua resposta! Certifique-se de ler as Perguntas frequentes sobre autopromoção com atenção. Observe também que é necessário que você publique um aviso de isenção de responsabilidade toda vez que criar um link para seu próprio site / produto.
Andrew Barber

3
Infelizmente, o link github wwjamieson3 / visionionTools está quebrado.
Brenda J. Butler

@williamJamieson is visionionTools é um repositório GitHub privado?
eebbesen

-5

Parece que escrever um script para fazer isso é muito fácil. Essencialmente, ele precisa iterar nos repositórios e então usar comandos como git ls-files, git diff e git log.


Eu sei que é tarde, mas você poderia publicar o roteiro?
10b0

Não existe "o script". Estou usando um script que escrevi para minhas próprias necessidades, mas não é genérico.
iny

"git diff" é realmente complicado se você deseja obter um único arquivo diff que pode ser revertido e reaplicado com um único comando patch.
proski

4
Literalmente, qualquer uma das respostas deve ser aceita, exceto esta.
Kennet Celeste de
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.