CLI único em Go para operar o git em vários projetos ao mesmo tempo: atualizar a
branch principal, criar branches novas, alternar entre branches, abrir PRs com
mensagem gerada pelo claude, revisar e corrigir os apontamentos do PR.
make build # gera ./bin/git-manager
make install # instala em ~/.local/bin e cria o atalho gmRequisitos: Go 1.26+, git, e — para as tarefas pr, review e fix — o
claude no PATH. As tarefas pr, draft e ready também precisam, conforme o
provider de cada projeto:
github: ogh(GitHub CLI) autenticado;bitbucket: um API token da conta Atlassian (id.atlassian.com → Security → API tokens → "Create API token with scopes") com os escoposread:repository:bitbucket,read:pullrequest:bitbucketewrite:pullrequest:bitbucket, informado embitbucket.tokenou na variávelBITBUCKET_TOKEN, junto com o e-mail da conta embitbucket.emailou na variávelBITBUCKET_EMAIL. A autenticação é Basic (e-mail + token); tokens de acesso de repositório/workspace não são aceitos.
Arquivo .yml com a lista de projetos:
bitbucket:
email: ${BITBUCKET_EMAIL}
token: ${BITBUCKET_TOKEN}
projects:
- name: backend
provider: bitbucket
path: /Users/sergio/projects/backend
main: true
major-branch: develop
commit-sufixo: teste-teste-teste
- name: admin
provider: bitbucket
path: /Users/sergio/projects/frontend-admin
main: true
- name: client
provider: github
path: /Users/sergio/projects/frontend-client
main: false| chave | obrigatória | descrição |
|---|---|---|
name |
sim | nome usado em --project=nome |
provider |
sim | github ou bitbucket; define como os PRs são criados e alterados |
path |
sim | diretório do repositório (aceita ~ e variáveis de ambiente) |
main |
sim | define se o projeto entra nas execuções sem --no-main |
major-branch |
não | branch principal do projeto: origem das tarefas update, new e checkout e destino da tarefa pr; sem ela, --source/--target passam a ser obrigatórios |
commit-sufixo |
não | string acrescentada ao fim da mensagem de commit da tarefa pr |
As chaves bitbucket.email e bitbucket.token só são necessárias se algum
projeto usar provider: bitbucket. Aceitam o valor literal ou uma variável de
ambiente (${NOME}); se estiverem vazias, as variáveis BITBUCKET_EMAIL e
BITBUCKET_TOKEN são usadas. O
workspace e o repositório são extraídos da URL do remote origin (ssh ou
https), que precisa apontar para bitbucket.org.
Ordem de busca do arquivo quando --config não é informado:
- variável de ambiente
GIT_MANAGER_CONFIG; - diretório atual:
git-manager.yml,git-manager.yaml,projects.yml,projects.yaml,config.yml,config.yaml; ~/.config/git-manager/config.yml(e.yaml);~/.git-manager.yml(e.yaml).
git-manager <tarefa> [parâmetros]
gm <tarefa> [parâmetros] # atalho criado pelo make installOs parâmetros com valor aceitam -p backend, -p=backend, --project backend
ou --project=backend.
| parâmetro | efeito |
|---|---|
--no-main |
executa em todos os projetos, inclusive os com main: false |
-p, --project=nome |
executa apenas no(s) projeto(s) informado(s) (ignora o filtro de main) |
-b, --branch=nome |
nome da branch (obrigatório nas tarefas new e checkout; opcional nas draft e ready) |
-s, --source=nome |
branch de origem nas tarefas update, new e checkout; substitui o major-branch do config e é obrigatório quando algum projeto selecionado não o define |
-t, --target=nome |
branch de destino na tarefa pr; substitui o major-branch do config e é obrigatório quando algum projeto selecionado não o define |
--config=arquivo.yml |
caminho do arquivo de configuração |
--dry-run |
imprime os comandos sem aplicar nenhuma alteração |
Sem --no-main e sem --project, a tarefa roda somente nos projetos com
main: true.
Nas tarefas update, new e checkout, a branch de origem é o --source,
quando informado; na tarefa pr, a branch de destino é o --target. Sem o
parâmetro, ambas usam o major-branch de cada projeto no config. A execução
falha antes de tocar em qualquer projeto se, sem o parâmetro, algum projeto
selecionado não tiver major-branch ou se os projetos selecionados tiverem
major-branch diferentes — a tarefa sempre usa uma única branch para todos os
projetos da execução.
--project aceita múltiplos nomes separados por vírgula (ex.:
--project=backend,admin), executando a tarefa em cada um deles, na ordem
informada. Nomes repetidos são ignorados e um nome inexistente falha a
execução inteira.
Não altera nada no repositório: faz git fetch --prune origin (para o
ahead/behind refletir o remoto) e mostra, para a branch atual:
- se está limpa ou o número de arquivos alterados (staged, não staged, não rastreados e em conflito);
- a situação com o upstream (
origin/<branch>): em dia, sem upstream configurado, ou quantos commits à frente/atrás; - quando a branch atual não é a principal: quantos commits à frente/atrás ela
está de
origin/<principal>.
git-manager status --no-mainAtualiza a branch de origem (--source ou major-branch), que precisa
existir em origin; caso contrário a tarefa falha sem alterar o repositório.
git fetch --prune origin;- se a branch atual tiver alterações não commitadas (e não for a de origem):
git add --all,git commit --no-verify -m "processo automático"egit push --force origin <branch>; git checkout <origem>(com--forcecaso o checkout normal seja bloqueado);git pull origin <origem>; se a branch de origem tiver alterações locais ou o pull for bloqueado, aplicagit reset --hard origin/<origem>.
git-manager update # origem: major-branch do config
git-manager update --source=develop --no-main # origem explícita para todosExecuta o update e em seguida git checkout -b nome, criando a branch a
partir da branch de origem. Se a branch já existir localmente, apenas faz o
checkout nela e avisa.
git-manager new --branch=feature/login --no-mainExecuta o update — inclusive o commit automático com a mensagem
processo automático e o force push da branch atual — e em seguida entra na
branch informada:
- se ela existir localmente:
git checkout <nome>; - senão, se existir em
origin:git checkout -b <nome> --track origin/<nome>; - se não existir em nenhum dos dois, a tarefa falha e indica o uso do
new.
Depois do checkout, a branch de origem é mesclada nela com
git merge --no-edit <origem>, para que a branch informada também fique
atualizada (não só a de origem). A mensagem do merge é gerada automaticamente
pelo git, sem abrir editor. Se o merge gerar conflito, a tarefa falha e o
merge fica em andamento para resolução manual (resolva os conflitos e finalize
com git commit, como em qualquer merge normal).
Informar a própria branch de origem é aceito: o update já deixa o
repositório nela, atualizada.
git-manager checkout --branch=feature/login --no-mainAbre o PR contra a branch de destino (--target ou major-branch).
git add --all;- gera título e descrição com
claude -p "@pr-message gere a mensagem das alterações no formato markdown" --allowedTools "Read,Edit,Bash,Git"; git commit --no-verify -m "<title> <commit-sufixo>";git push --set-upstream origin <branch>(com fallback para--force);- abre o PR em draft contra a branch de destino, usando o
titlecomo título e omessagecomo descrição:github:gh pr create --draft --assignee @me, atribuído ao usuário autenticado nogh;bitbucket:POST /2.0/repositories/<workspace>/<repo>/pullrequestscomdraft: true(o autor é o dono do token; Bitbucket não tem assignee).
Chamadas ao GitHub/Bitbucket que falham por indisponibilidade (HTTP 5xx,
timeout) são repetidas até três vezes. No GitHub, se ainda assim a criação com
assignee falhar, o PR é criado sem assignee e a atribuição é tentada em seguida
com gh pr edit --add-assignee @me; persistindo o erro, um aviso pede a
atribuição manual.
Se já existir um PR aberto para a branch, o push atualiza o PR existente, a URL
é exibida no resumo e, no GitHub, se ele não tiver assignee, é atribuído a você.
A tarefa falha se a branch atual for a própria branch de destino, se a branch de
destino não existir em origin ou se não houver diferença em relação a ela.
A leitura da resposta do claude aceita três formatos, nesta ordem: as seções
title:/message: (com ou sem blocos ); dois blocos sem rótulo, sendo o
primeiro o título e o segundo a descrição — formato comum no modo -p, que
costuma perder os rótulos e acrescentar um preâmbulo; ou um único bloco ```, em
que a primeira linha vira o título e o restante a descrição. Texto sem nenhum
bloco é recusado com erro, e a saída bruta é impressa para conferência.
Converte para draft o PR da branch atual, usando gh pr ready <n> --undo
(GitHub) ou PUT .../pullrequests/<n> com draft: true (Bitbucket). Com
--branch=nome o PR daquela branch é usado sem trocar de branch no repositório.
- se não houver PR aberto para a branch, a tarefa falha;
- se o PR já estiver em draft, nada é alterado e o resumo informa isso.
git-manager draft --no-main
git-manager draft --branch=SYSVET-924 --project=backendMarca como pronto para revisão o PR da branch atual, usando gh pr ready <n>
(GitHub) ou PUT .../pullrequests/<n> com draft: false (Bitbucket). Com
--branch=nome o PR daquela branch é usado sem trocar de branch no repositório.
- se não houver PR aberto para a branch, a tarefa falha;
- se o PR já estiver pronto para revisão, nada é alterado e o resumo informa isso.
git-manager ready --no-main
git-manager ready --branch=SYSVET-924 --project=backendclaude -p "@pr-reviewer revise o pr da branch atual" --allowedTools "Read,Edit,Bash,Git",
com a saída transmitida em tempo real.
Os agentes pr-reviewer e pr-comment-fixer usam o gh internamente, portanto
review e fix só funcionam em projetos hospedados no GitHub.
claude -p "@pr-comment-fixer corrija os apontamentos feitos no pr a branch corrente mesmo que forem problemas pré-existentes, pode corrigir" --allowedTools "Read,Edit,Bash,Git".
git fetch --prune origin;- lista as branches locais cujo upstream foi removido (
[gone]nogit for-each-ref --format='%(upstream:track)'); - remove cada uma com
git branch -D, pulando a branch atualmente selecionada (com aviso) caso ela esteja nessa lista.
git-manager prune --no-maingit-manager update # projetos main: true, origem: major-branch
git-manager update --no-main # todos os projetos
git-manager update --source=develop --no-main # origem explícita para todos
git-manager new --branch=feature/login --no-main
git-manager checkout --branch=feature/login --no-main
git-manager pr --project=backend # destino: major-branch do config
git-manager pr --target=release/2.0 --no-main # destino explícito para todos
git-manager draft --no-main # PR da branch atual volta a draft
git-manager ready --no-main # PR da branch atual sai do draft
git-manager review --no-main
git-manager fix --project=backend
git-manager prune --project=backend,admin # múltiplos projetos
git-manager update --no-main --dry-run # simula, sem alterar nada- todos os commits usam
--no-verify; - a branch principal usada pela tarefa
statusé detectada pororigin/HEADe, na ausência dela, pormaine depoismaster; as demais tarefas usam amajor-branch(ou--source/--target); - o
commit-sufixoé aplicado no commit da tarefapr; o commit automático doupdatemantém a mensagem fixaprocesso automático; - quando a branch atual é a de origem e existem alterações locais, elas são
descartadas pelo
reset --hard origin/<origem>(regra 5.1.b), em vez de gerarem um force push na branch de origem; - os projetos são processados em sequência e o resumo final lista o resultado de cada um; o processo sai com código 1 se algum projeto falhar.
make fmt
make vet
make test