Created
April 9, 2025 19:15
-
-
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)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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