Skip to content

Instantly share code, notes, and snippets.

@rodrigosimoesrosa
Created April 9, 2025 19:15
Show Gist options
  • Save rodrigosimoesrosa/de7454ef197b26c784549f0c8a7dfc49 to your computer and use it in GitHub Desktop.
Save rodrigosimoesrosa/de7454ef197b26c784549f0c8a7dfc49 to your computer and use it in GitHub Desktop.
Manage multiple git accounts script (macOS/Sonoma 14.5) (Linux/Ubuntu 24.04.2 LTS)
#!/bin/bash
CONFIG_DIR="$HOME/.git_account_manager"
mkdir -p "$CONFIG_DIR"
CONFIG_FILE="$CONFIG_DIR/configs.json"
CURRENT_FILE="$CONFIG_DIR/current.json"
SSH_CONFIG="$HOME/.ssh/config"
mkdir -p "$HOME/.ssh"
if [ ! -f "$CONFIG_FILE" ]; then
echo "[]" > "$CONFIG_FILE"
fi
function listar_ssh_config() {
if [ -f "$SSH_CONFIG" ]; then
echo "🔍 Entradas encontradas em ~/.ssh/config:"
grep -i "^Host " "$SSH_CONFIG" | awk '{print " - "$2}'
else
echo "⚠️ Nenhum ~/.ssh/config encontrado."
fi
}
function aplicar_git_config() {
local nome="$1"
local email="$2"
local escopo="$3"
local -n projetos_ref=$4
if [[ "$escopo" == "global" ]]; then
git config --global user.name "$nome"
git config --global user.email "$email"
echo "✅ Configurações aplicadas globalmente para $nome <$email>"
echo "{\"nome\": \"$nome\", \"email\": \"$email\"}" > "$CURRENT_FILE"
else
for projeto in "${projetos_ref[@]}"; do
if [ -d "$projeto/.git" ]; then
git -C "$projeto" config user.name "$nome"
git -C "$projeto" config user.email "$email"
echo "✅ Configurações aplicadas localmente em $projeto"
else
echo "⚠️ Diretório não é um repositório Git: $projeto"
fi
done
fi
}
function aplicar_ssh() {
if [ ! -f "$1" ]; then
echo "❌ Chave SSH não encontrada: $1"
return 1
fi
eval "$(ssh-agent -s)" > /dev/null
chmod 600 "$1"
ssh-add "$1"
echo "🔐 Chave SSH adicionada: $1"
}
function atualizar_ssh_config() {
local host_alias=$1
local host_name=$2
local chave_path=$3
touch "$SSH_CONFIG"
if grep -q "Host $host_alias" "$SSH_CONFIG"; then
awk -v alias="$host_alias" '
BEGIN {skip=0}
/^Host / {skip=($2 == alias)}
!skip
' "$SSH_CONFIG" > "$SSH_CONFIG.tmp" && mv "$SSH_CONFIG.tmp" "$SSH_CONFIG"
fi
{
echo ""
echo "Host $host_alias"
echo " HostName $host_name"
echo " User git"
echo " IdentityFile $chave_path"
echo " IdentitiesOnly yes"
} >> "$SSH_CONFIG"
echo "📄 Entrada adicionada ao ~/.ssh/config (Host: $host_alias)"
}
function gerar_ou_escolher_ssh() {
read -p "Deseja criar uma nova chave SSH para esta conta? (s/n): " gerar
if [[ "$gerar" == "s" ]]; then
ssh_path="$HOME/.ssh/id_$(echo "$1" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9_')"
ssh-keygen -t ed25519 -f "$ssh_path" -C "$2" -q -N ""
aplicar_ssh "$ssh_path" >&2 || return 1
echo "📋 Copie esta chave para o GitHub/GitLab:" >&2
cat "${ssh_path}.pub" >&2
else
read -p "Digite o caminho da chave SSH existente (ex: ~/.ssh/id_nome): " ssh_path
ssh_path_expanded=$(eval echo "$ssh_path")
if [ ! -f "$ssh_path_expanded" ]; then
echo "❌ Caminho inválido: $ssh_path_expanded" >&2
return 1
fi
aplicar_ssh "$ssh_path_expanded" >&2 || return 1
ssh_path="$ssh_path_expanded"
fi
host_alias="git-$(echo "$1" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9_-')"
host_alias=$(echo "$host_alias" | sed 's/-*$//')
atualizar_ssh_config "$host_alias" "github.com" "$ssh_path" >&2
echo "$ssh_path"
}
function adicionar_conta() {
read -p "Nome da conta Git: " nome
read -p "Email da conta Git: " email
if [[ -z "$nome" || -z "$email" ]]; then
echo "❌ Nome e email são obrigatórios."
return
fi
if jq -e --arg n "$nome" --arg e "$email" '.[] | select(.nome == $n and .email == $e)' "$CONFIG_FILE" > /dev/null; then
echo "⚠️ Conta já existe!"
return
fi
ssh_key_path=$(gerar_ou_escolher_ssh "$nome" "$email")
if [[ -z "$ssh_key_path" || ! -f "$ssh_key_path" ]]; then
echo "❌ Erro ao configurar chave SSH. Conta não adicionada. Caminho: $ssh_key_path"
return
fi
read -p "Deseja aplicar essa conta como global (g) ou local (l)? " escopo
if [[ "$escopo" == "l" ]]; then
read -p "Digite os caminhos dos projetos separados por vírgula: " projetos_input
IFS=',' read -ra projetos <<< "$projetos_input"
else
escopo="global"
projetos=()
fi
tmp=$(mktemp)
jq --arg nome "$nome" --arg email "$email" --arg chave "$ssh_key_path" --arg escopo "$escopo" --argjson projetos "$(printf '%s\n' "${projetos[@]}" | jq -R . | jq -s .)" \
'. += [{"nome": $nome, "email": $email, "chave": $chave, "escopo": $escopo, "projetos": $projetos}]' "$CONFIG_FILE" > "$tmp" && mv "$tmp" "$CONFIG_FILE"
echo "✅ Conta adicionada!"
}
function listar_contas() {
total=$(jq '. | length' "$CONFIG_FILE")
if [[ "$total" -eq 0 ]]; then
echo "Nenhuma conta configurada ainda."
return
fi
echo "📜 Contas configuradas:"
jq -r 'to_entries[] | "\(.key + 1). \(.value.nome) <\(.value.email)> [\(.value.chave)] (\(.value.escopo))"' "$CONFIG_FILE"
}
function selecionar_conta() {
listar_contas
read -p "Digite o número da conta para aplicar: " num
total=$(jq '. | length' "$CONFIG_FILE")
if (( num < 1 || num > total )); then
echo "❌ Número inválido."
return
fi
index=$((num - 1))
nome=$(jq -r ".[$index].nome" "$CONFIG_FILE")
email=$(jq -r ".[$index].email" "$CONFIG_FILE")
chave=$(jq -r ".[$index].chave" "$CONFIG_FILE")
escopo=$(jq -r ".[$index].escopo // \"global\"" "$CONFIG_FILE")
readarray -t projetos < <(jq -r ".[$index].projetos // [] | .[]" "$CONFIG_FILE")
aplicar_git_config "$nome" "$email" "$escopo" projetos
aplicar_ssh "$chave"
host_alias="git-$(echo "$nome" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9_-')"
host_alias=$(echo "$host_alias" | sed 's/-*$//')
atualizar_ssh_config "$host_alias" "github.com" "$chave"
}
function remover_conta() {
listar_contas
read -p "Digite o número da conta para remover: " num
total=$(jq '. | length' "$CONFIG_FILE")
if (( num < 1 || num > total )); then
echo "❌ Número inválido."
return
fi
index=$((num - 1))
nome=$(jq -r ".[$index].nome" "$CONFIG_FILE")
chave=$(jq -r ".[$index].chave" "$CONFIG_FILE")
host_alias="git-$(echo "$nome" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9_-')"
host_alias=$(echo "$host_alias" | sed 's/-*$//')
if grep -q "Host $host_alias" "$SSH_CONFIG"; then
awk -v alias="$host_alias" '
BEGIN { skip=0 }
{
if ($1 == "Host" && $2 == alias) {
skip = 1
next
}
if (skip && $1 == "Host") {
skip = 0
}
if (!skip) print
}
' "$SSH_CONFIG" > "$SSH_CONFIG.tmp" && mv "$SSH_CONFIG.tmp" "$SSH_CONFIG"
echo "🧹 Entrada SSH removida de ~/.ssh/config (Host: $host_alias)"
else
echo "⚠️ Nenhuma entrada SSH encontrada para Host: $host_alias"
fi
if ssh-add -l | grep -q "$chave"; then
ssh-add -d "$chave" && echo "🗑️ Chave removida do ssh-agent: $chave"
fi
tmp=$(mktemp)
jq "del(.[$index])" "$CONFIG_FILE" > "$tmp" && mv "$tmp" "$CONFIG_FILE"
echo "🗑️ Conta removida com sucesso."
}
function mostrar_conta_atual() {
if [ -f "$CURRENT_FILE" ]; then
nome=$(jq -r '.nome' "$CURRENT_FILE")
email=$(jq -r '.email' "$CURRENT_FILE")
echo "🟢 Conta atual: $nome <$email>"
fi
}
function exportar_backup() {
cp "$CONFIG_FILE" "$CONFIG_DIR/backup_$(date +%Y%m%d%H%M%S).json"
echo "💾 Backup exportado para $CONFIG_DIR"
}
function gerar_git_remote() {
listar_contas
read -p "Digite o número da conta para gerar o remote: " num
total=$(jq '. | length' "$CONFIG_FILE")
if (( num < 1 || num > total )); then
echo "❌ Número inválido."
return
fi
index=$((num - 1))
nome=$(jq -r ".[$index].nome" "$CONFIG_FILE")
# Gera o host alias com base no nome
host_alias="git-$(echo "$nome" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9_-')"
host_alias=$(echo "$host_alias" | sed 's/-*$//')
read -p "Cole a URL do repositório SSH (ex: [email protected]:usuario/repositorio.git): " url_original
if [[ "$url_original" =~ ^git@github\.com:(.*)$ ]]; then
repo_path="${BASH_REMATCH[1]}"
nova_url="git@$host_alias:$repo_path"
echo ""
echo "🔗 Nova URL com Host personalizado:"
echo "$nova_url"
echo ""
echo "💡 Você pode usá-la com:"
echo " git remote set-url origin $nova_url"
echo "ou:"
echo " git remote add origin $nova_url"
else
echo "❌ URL inválida. Deve ser no formato [email protected]:usuario/repositorio.git"
fi
}
# Menu principal
while true; do
echo ""
echo "==== Gerenciador de Contas Git ===="
mostrar_conta_atual
echo "1. Adicionar nova conta"
echo "2. Listar contas"
echo "3. Aplicar conta"
echo "4. Remover conta"
echo "5. Exportar backup"
echo "6. Gerar URL de git remote com Host personalizado"
echo "7. Sair"
read -p "Escolha uma opção: " opcao
case $opcao in
1) adicionar_conta ;;
2) listar_contas ;;
3) selecionar_conta ;;
4) remover_conta ;;
5) exportar_backup ;;
6) gerar_git_remote ;;
7) echo "👋 Até logo!"; exit 0 ;;
*) echo "⚠️ Opção inválida!" ;;
esac
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment