Contenuti




Git Setup e Sincronizzazione Avanzata: Guida Completa per Repository Management

Configurazione, autenticazione token, sincronizzazione e automazione per Git su Linux e Windows


Git Setup e Sincronizzazione Avanzata: Guida Completa per Repository Management

Git è il cuore dello sviluppo moderno, ma una configurazione corretta e strategie di sincronizzazione efficaci sono essenziali per un workflow produttivo. Questa guida pratica ti accompagna dalla configurazione iniziale agli script di automazione avanzati.

Cosa imparerai in questa guida
  • Configurazione Git Completa: Setup username/email globale e locale
  • Autenticazione Sicura: Generazione e configurazione token per GitHub/GitLab
  • Sincronizzazione Repository: Clonazione e setup su sistemi Linux
  • Gestione Conflitti: Come forzare il repository remoto sovrascrivendo modifiche locali
  • Automazione Avanzata: Script Bash e PowerShell per sincronizzazione automatica
  • Best Practices: Strategie per repository multipli e team workflow

Indice della Guida

  1. Configurazione Git: Username e Email
  2. Autenticazione con Token su Linux
  3. Sincronizzazione Repository
  4. Gestione Conflitti e Force Sync
  5. Script di Automazione Bash
  6. Script di Automazione PowerShell
  7. Schedulazione e Monitoring
  8. Troubleshooting Comune

Configurazione Git: Username e Email

Setup Globale di Base

La configurazione globale di Git è il punto di partenza per qualsiasi workflow. Questi comandi imposteranno le informazioni utilizzate per tutti i repository sul sistema.

1
2
3
4
5
6
# Configurazione identità globale (obbligatorio)
git config --global user.name "Il Tuo Nome Completo"
git config --global user.email "tua.email@esempio.com"

# Verifica configurazione
git config --global --list | grep user
Configurazione Email
Importante: Usa l’email associata al tuo account GitHub/GitLab per collegare correttamente i commit al tuo profilo e abilitare le statistiche di contribuzione.

Configurazioni Globali Avanzate

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Editor di default per commit message
git config --global core.editor "nano"          # Nano (semplice)
git config --global core.editor "vim"           # Vim (avanzato)
git config --global core.editor "code --wait"   # VS Code

# Comportamento line endings (importante per cross-platform)
git config --global core.autocrlf input         # Linux/macOS
git config --global core.autocrlf true          # Windows

# Configurazione colori per output più leggibile
git config --global color.ui auto

# Strategia di merge default
git config --global pull.rebase false          # Merge (default)
git config --global pull.rebase true           # Rebase automatico

# Push behavior sicuro
git config --global push.default simple

# Credenziali helper (memorizza credenziali)
git config --global credential.helper store    # Store permanente
git config --global credential.helper cache    # Cache temporanea (15min default)

Configurazione Specifica per Repository

Per progetti con requisiti diversi, puoi sovrascrivere la configurazione globale:

1
2
3
4
5
6
7
8
9
# Naviga nella directory del repository
cd /path/to/your/repository

# Configurazione locale (sovrascrive quella globale)
git config --local user.name "Nome Specifico Progetto"
git config --local user.email "email.progetto@azienda.com"

# Verifica configurazioni attive per il repository
git config --list --show-origin

Visualizzazione e Gestione Configurazioni

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# Mostra tutte le configurazioni
git config --list

# Configurazioni solo globali
git config --global --list

# Configurazioni solo locali
git config --local --list

# Verifica valore specifico
git config user.name
git config user.email

# Rimuovi configurazione specifica
git config --global --unset user.name
git config --local --unset user.email

# Modifica configurazione con editor
git config --global --edit

Autenticazione con Token su Linux

Generazione Token GitHub

Dal 2021, GitHub richiede l’autenticazione tramite Personal Access Token (PAT) invece delle password.

Deprecazione Password
GitHub ha deprecato l’autenticazione tramite password per le operazioni Git. È obbligatorio utilizzare Personal Access Token o chiavi SSH.

Creazione Token su GitHub

  1. Accedi a GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)

  2. Genera nuovo token:

    1
    2
    3
    4
    5
    6
    7
    
    Name: Git Operations - [Nome Macchina/Progetto]
    Expiration: 90 days (consigliato per sicurezza)
    
    Scopes richiesti:
    ✓ repo (accesso completo ai repository)
    ✓ workflow (per GitHub Actions, se necessario)
    ✓ write:packages (per GitHub Packages, se necessario)
    
  3. Copia il token (visibile solo una volta!)

Configurazione Token su Linux

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Metodo 1: Configurazione nel URL del remote
git remote set-url origin https://username:YOUR_TOKEN@github.com/username/repository.git

# Metodo 2: Store credential helper (più sicuro)
git config --global credential.helper store
# Al prossimo push/pull, inserisci:
# Username: il_tuo_username
# Password: YOUR_TOKEN

# Verifica configurazione remote
git remote -v

Generazione Token GitLab

Per GitLab il processo è simile ma leggermente diverso:

Creazione Token su GitLab

  1. Accedi a GitLab → User Settings → Access Tokens

  2. Crea Personal Access Token:

    1
    2
    3
    4
    5
    6
    7
    
    Name: Git Operations - [Descrizione]
    Expiration date: [Data scadenza]
    
    Scopes richiesti:
    ✓ read_repository
    ✓ write_repository
    ✓ api (se usi GitLab API)
    

Configurazione Token GitLab su Linux

1
2
3
4
5
# Configurazione URL con token
git remote set-url origin https://oauth2:YOUR_GITLAB_TOKEN@gitlab.com/username/repository.git

# Oppure con username specifico
git remote set-url origin https://username:YOUR_GITLAB_TOKEN@gitlab.com/username/repository.git

Gestione Sicura dei Token

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Memorizza credenziali in file sicuro
git config --global credential.helper 'store --file ~/.git-credentials'

# Imposta permessi sicuri al file
chmod 600 ~/.git-credentials

# Oppure usa credential helper con cache temporanea
git config --global credential.helper 'cache --timeout=3600'  # 1 ora

# Per rimuovere credenziali memorizzate
git config --global --unset credential.helper
rm ~/.git-credentials
Sicurezza Token
  • Mai hardcodare token nei file di configurazione del progetto
  • Usa scadenze ragionevoli (30-90 giorni)
  • Rigenera periodicamente i token
  • Revoca immediatamente token compromessi
  • Considera l’uso di SSH keys per ambienti di produzione

Sincronizzazione Repository

Clonazione Repository con Token

1
2
3
4
5
6
7
8
9
# Clonazione HTTPS con token incorporato
git clone https://username:TOKEN@github.com/username/repository.git

# Clonazione standard (richiederà credenziali)
git clone https://github.com/username/repository.git
cd repository

# Configura remote con token (dopo clonazione standard)
git remote set-url origin https://username:TOKEN@github.com/username/repository.git

Setup Repository Esistente

Se hai già un repository locale da sincronizzare:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Naviga nella directory del progetto
cd /path/to/existing/project

# Inizializza repository Git
git init

# Aggiungi remote origin
git remote add origin https://username:TOKEN@github.com/username/repository.git

# Verifica connessione
git remote -v

# Primo push (se repository remoto vuoto)
git add .
git commit -m "Initial commit"
git branch -M main
git push -u origin main

Sincronizzazione con Repository Esistente

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Se il repository remoto ha già contenuti
git remote add origin https://username:TOKEN@github.com/username/repository.git

# Fetch del contenuto remoto
git fetch origin

# Merge con contenuto remoto (attenzione ai conflitti)
git merge origin/main --allow-unrelated-histories

# Oppure reset per sovrascrivere completamente il locale
git reset --hard origin/main

# Push delle modifiche future
git push -u origin main

Gestione Conflitti e Force Sync

Ignorare Modifiche Locali e Forzare Repository Remoto

Spesso è necessario sovrascrivere completamente le modifiche locali con quelle del repository remoto:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Metodo 1: Reset Hard (perdita totale delle modifiche locali)
git fetch origin
git reset --hard origin/main
git clean -fd  # Rimuove file untracked

# Metodo 2: Stash e Pull
git stash push -m "Backup modifiche locali prima del force sync"
git pull --force origin main

# Metodo 3: Force Pull completo
git fetch --all
git reset --hard origin/main

Force Sync con Backup delle Modifiche

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Backup delle modifiche locali prima del force sync
git stash push -m "Backup $(date '+%Y-%m-%d %H:%M:%S')"

# Force sync dal remoto
git fetch origin
git reset --hard origin/main
git clean -fd

# Verifica stash (per eventuale recupero)
git stash list

# Per ripristinare le modifiche salvate (se necessario)
# git stash pop stash@{0}

Sovrascrivere Branch Specifico

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Force sync di un branch specifico
git checkout branch-name
git fetch origin
git reset --hard origin/branch-name

# Oppure per tutti i branch
git fetch --all
for branch in $(git branch -r | grep -v '\->'); do
    git checkout ${branch#origin/}
    git reset --hard $branch
done
git checkout main
Attenzione Force Operations
Le operazioni di force sync eliminano permanentemente le modifiche locali non committate. Usa sempre backup o stash prima di eseguire queste operazioni.

Ripristino di Sicurezza

1
2
3
4
5
6
7
8
# Se hai fatto un errore, puoi recuperare usando reflog
git reflog  # Mostra la storia delle operazioni

# Ripristina a stato precedente
git reset --hard HEAD@{n}  # dove n è il numero dall'reflog

# Oppure crea un branch di backup prima del force sync
git branch backup-$(date +%Y%m%d-%H%M%S)

Script di Automazione Bash

Script Base per Sincronizzazione

Crea uno script bash completo per automatizzare la sincronizzazione:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/bin/bash

# git_sync.sh - Script automazione sincronizzazione Git
# Utilizzo: ./git_sync.sh [directory_repo] [branch]

# Configurazione
REPO_DIR="${1:-$(pwd)}"
BRANCH="${2:-main}"
LOG_FILE="$HOME/git_sync.log"
MAX_LOG_SIZE=10485760  # 10MB

# Colori per output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Funzione logging
log_message() {
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo -e "${timestamp} - $1" | tee -a "$LOG_FILE"
}

# Funzione rotazione log
rotate_log() {
    if [[ -f "$LOG_FILE" ]] && [[ $(stat -c%s "$LOG_FILE") -gt $MAX_LOG_SIZE ]]; then
        mv "$LOG_FILE" "${LOG_FILE}.old"
        log_message "Log rotated - previous log saved as ${LOG_FILE}.old"
    fi
}

# Controllo directory repository
check_repository() {
    if [[ ! -d "$REPO_DIR/.git" ]]; then
        log_message "${RED}ERROR: $REPO_DIR non è una directory Git valida${NC}"
        exit 1
    fi
}

# Backup modifiche locali
backup_local_changes() {
    cd "$REPO_DIR" || exit 1

    if ! git diff-index --quiet HEAD --; then
        log_message "${YELLOW}Backup modifiche locali non committate...${NC}"
        git stash push -m "Auto-backup $(date '+%Y-%m-%d %H:%M:%S')" 2>/dev/null
        if [[ $? -eq 0 ]]; then
            log_message "${GREEN}Modifiche locali salvate in stash${NC}"
        else
            log_message "${RED}Errore durante il backup delle modifiche locali${NC}"
        fi
    fi
}

# Sincronizzazione repository
sync_repository() {
    cd "$REPO_DIR" || exit 1

    log_message "${BLUE}Inizio sincronizzazione repository: $REPO_DIR${NC}"

    # Fetch ultimo contenuto
    log_message "Fetch da remote..."
    if git fetch origin 2>>"$LOG_FILE"; then
        log_message "${GREEN}Fetch completato con successo${NC}"
    else
        log_message "${RED}Errore durante fetch${NC}"
        return 1
    fi

    # Checkout branch target
    log_message "Checkout branch: $BRANCH"
    if git checkout "$BRANCH" 2>>"$LOG_FILE"; then
        log_message "${GREEN}Checkout completato${NC}"
    else
        log_message "${RED}Errore durante checkout di $BRANCH${NC}"
        return 1
    fi

    # Force sync con remote
    log_message "Force sync con origin/$BRANCH..."
    if git reset --hard "origin/$BRANCH" 2>>"$LOG_FILE"; then
        log_message "${GREEN}Force sync completato${NC}"
    else
        log_message "${RED}Errore durante force sync${NC}"
        return 1
    fi

    # Pulizia file untracked
    log_message "Pulizia file untracked..."
    git clean -fd 2>>"$LOG_FILE"

    # Informazioni finali
    local current_commit=$(git rev-parse --short HEAD)
    local commit_message=$(git log -1 --pretty=format:'%s')
    log_message "${GREEN}Sincronizzazione completata${NC}"
    log_message "Commit corrente: $current_commit - $commit_message"

    return 0
}

# Controllo connettività
check_connectivity() {
    cd "$REPO_DIR" || exit 1

    log_message "Controllo connettività remote..."
    if git ls-remote --exit-code origin HEAD >/dev/null 2>&1; then
        log_message "${GREEN}Connettività OK${NC}"
        return 0
    else
        log_message "${RED}Errore di connettività al repository remote${NC}"
        return 1
    fi
}

# Funzione principale
main() {
    rotate_log
    log_message "${BLUE}=== Avvio Git Sync Script ===${NC}"

    check_repository

    if ! check_connectivity; then
        log_message "${RED}Script terminato per errore di connettività${NC}"
        exit 1
    fi

    backup_local_changes

    if sync_repository; then
        log_message "${GREEN}=== Sincronizzazione completata con successo ===${NC}"
        exit 0
    else
        log_message "${RED}=== Sincronizzazione fallita ===${NC}"
        exit 1
    fi
}

# Esecuzione script
main "$@"

Script Avanzato Multi-Repository

Per gestire multipli repository:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#!/bin/bash

# multi_git_sync.sh - Sincronizzazione multipli repository
# Configurazione via file JSON o array

# File configurazione repository
CONFIG_FILE="$HOME/.git_sync_config"

# Crea file configurazione se non esiste
create_config() {
    if [[ ! -f "$CONFIG_FILE" ]]; then
        cat > "$CONFIG_FILE" << 'EOF'
# Configurazione Git Sync - Un repository per riga
# Formato: /path/to/repo:branch_name:description
/home/user/project1:main:Progetto principale
/home/user/project2:development:Progetto di sviluppo
/var/www/website:master:Sito web aziendale
EOF
        echo "File configurazione creato: $CONFIG_FILE"
        echo "Modifica il file e riesegui lo script"
        exit 0
    fi
}

# Sincronizzazione multipla
sync_all_repositories() {
    local success_count=0
    local error_count=0

    while IFS=':' read -r repo_path branch description; do
        # Skip linee vuote e commenti
        [[ -z "$repo_path" ]] || [[ "$repo_path" =~ ^#.*$ ]] && continue

        echo "=================================="
        echo "Repository: $description"
        echo "Path: $repo_path"
        echo "Branch: $branch"
        echo "=================================="

        if ./git_sync.sh "$repo_path" "$branch"; then
            ((success_count++))
            echo "✓ $description - OK"
        else
            ((error_count++))
            echo "✗ $description - ERROR"
        fi

        echo ""
        sleep 2  # Pausa tra repository

    done < "$CONFIG_FILE"

    echo "=================================="
    echo "RIEPILOGO SINCRONIZZAZIONE:"
    echo "Successi: $success_count"
    echo "Errori: $error_count"
    echo "=================================="
}

# Esecuzione
create_config
sync_all_repositories

Utilizzo Script Bash

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Rendi eseguibile lo script
chmod +x git_sync.sh
chmod +x multi_git_sync.sh

# Utilizzo base
./git_sync.sh                          # Repository corrente, branch main
./git_sync.sh /path/to/repo            # Repository specifico, branch main
./git_sync.sh /path/to/repo development # Repository e branch specifici

# Sincronizzazione multipla
./multi_git_sync.sh

Script di Automazione PowerShell

Script Base PowerShell

Ecco l’equivalente PowerShell per sistemi Windows:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# GitSync.ps1 - Script PowerShell per sincronizzazione Git
param(
    [Parameter(Position=0)]
    [string]$RepositoryPath = (Get-Location).Path,

    [Parameter(Position=1)]
    [string]$Branch = "main",

    [switch]$Verbose
)

# Configurazione
$LogFile = Join-Path $env:USERPROFILE "git_sync.log"
$MaxLogSize = 10MB

# Colori per output
enum LogLevel {
    Info
    Warning
    Error
    Success
}

# Funzione logging
function Write-LogMessage {
    param(
        [string]$Message,
        [LogLevel]$Level = [LogLevel]::Info
    )

    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "$timestamp - $Message"

    # Colori console
    $color = switch($Level) {
        "Info"    { "White" }
        "Warning" { "Yellow" }
        "Error"   { "Red" }
        "Success" { "Green" }
    }

    Write-Host $logEntry -ForegroundColor $color
    Add-Content -Path $LogFile -Value $logEntry
}

# Rotazione log
function Invoke-LogRotation {
    if (Test-Path $LogFile) {
        $logSize = (Get-Item $LogFile).Length
        if ($logSize -gt $MaxLogSize) {
            $oldLogFile = "${LogFile}.old"
            Move-Item -Path $LogFile -Destination $oldLogFile -Force
            Write-LogMessage "Log rotated - previous log saved as $oldLogFile" -Level Success
        }
    }
}

# Controllo repository Git
function Test-GitRepository {
    param([string]$Path)

    if (-not (Test-Path (Join-Path $Path ".git"))) {
        Write-LogMessage "ERROR: $Path is not a valid Git repository" -Level Error
        return $false
    }
    return $true
}

# Backup modifiche locali
function Backup-LocalChanges {
    param([string]$RepoPath)

    Push-Location $RepoPath

    try {
        # Controlla se ci sono modifiche non committate
        $status = git status --porcelain 2>$null
        if ($status) {
            Write-LogMessage "Backing up uncommitted local changes..." -Level Warning

            $stashMessage = "Auto-backup $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
            git stash push -m $stashMessage 2>$null

            if ($LASTEXITCODE -eq 0) {
                Write-LogMessage "Local changes saved to stash" -Level Success
            } else {
                Write-LogMessage "Error backing up local changes" -Level Error
            }
        }
    }
    finally {
        Pop-Location
    }
}

# Controllo connettività
function Test-GitConnectivity {
    param([string]$RepoPath)

    Push-Location $RepoPath

    try {
        Write-LogMessage "Testing remote connectivity..."

        $null = git ls-remote --exit-code origin HEAD 2>$null
        if ($LASTEXITCODE -eq 0) {
            Write-LogMessage "Connectivity OK" -Level Success
            return $true
        } else {
            Write-LogMessage "Remote connectivity error" -Level Error
            return $false
        }
    }
    finally {
        Pop-Location
    }
}

# Sincronizzazione repository
function Sync-GitRepository {
    param(
        [string]$RepoPath,
        [string]$TargetBranch
    )

    Push-Location $RepoPath

    try {
        Write-LogMessage "Starting repository sync: $RepoPath" -Level Info

        # Fetch
        Write-LogMessage "Fetching from remote..."
        git fetch origin 2>>$LogFile
        if ($LASTEXITCODE -ne 0) {
            Write-LogMessage "Error during fetch" -Level Error
            return $false
        }
        Write-LogMessage "Fetch completed successfully" -Level Success

        # Checkout branch
        Write-LogMessage "Checking out branch: $TargetBranch"
        git checkout $TargetBranch 2>>$LogFile
        if ($LASTEXITCODE -ne 0) {
            Write-LogMessage "Error checking out $TargetBranch" -Level Error
            return $false
        }
        Write-LogMessage "Checkout completed" -Level Success

        # Force sync
        Write-LogMessage "Force syncing with origin/$TargetBranch..."
        git reset --hard "origin/$TargetBranch" 2>>$LogFile
        if ($LASTEXITCODE -ne 0) {
            Write-LogMessage "Error during force sync" -Level Error
            return $false
        }
        Write-LogMessage "Force sync completed" -Level Success

        # Clean untracked files
        Write-LogMessage "Cleaning untracked files..."
        git clean -fd 2>>$LogFile

        # Final info
        $currentCommit = git rev-parse --short HEAD
        $commitMessage = git log -1 --pretty=format:'%s'
        Write-LogMessage "Sync completed successfully" -Level Success
        Write-LogMessage "Current commit: $currentCommit - $commitMessage" -Level Info

        return $true
    }
    finally {
        Pop-Location
    }
}

# Funzione principale
function Main {
    try {
        Invoke-LogRotation
        Write-LogMessage "=== Starting Git Sync Script ===" -Level Info

        # Controlli preliminari
        if (-not (Test-GitRepository -Path $RepositoryPath)) {
            exit 1
        }

        if (-not (Test-GitConnectivity -Path $RepositoryPath)) {
            Write-LogMessage "Script terminated due to connectivity error" -Level Error
            exit 1
        }

        # Backup e sincronizzazione
        Backup-LocalChanges -RepoPath $RepositoryPath

        if (Sync-GitRepository -RepoPath $RepositoryPath -TargetBranch $Branch) {
            Write-LogMessage "=== Synchronization completed successfully ===" -Level Success
            exit 0
        } else {
            Write-LogMessage "=== Synchronization failed ===" -Level Error
            exit 1
        }
    }
    catch {
        Write-LogMessage "Unexpected error: $($_.Exception.Message)" -Level Error
        exit 1
    }
}

# Esecuzione script
Main

Script Multi-Repository PowerShell

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# MultiGitSync.ps1 - Gestione multipli repository

param(
    [string]$ConfigFile = (Join-Path $env:USERPROFILE ".git_sync_config.json")
)

# Struttura configurazione
class GitRepository {
    [string]$Path
    [string]$Branch
    [string]$Description
    [bool]$Enabled = $true
}

# Crea file configurazione predefinito
function New-DefaultConfig {
    param([string]$ConfigPath)

    $defaultConfig = @(
        [GitRepository]@{
            Path = "C:\Projects\WebSite"
            Branch = "main"
            Description = "Sito web principale"
            Enabled = $true
        },
        [GitRepository]@{
            Path = "C:\Projects\API"
            Branch = "development"
            Description = "API Backend"
            Enabled = $true
        }
    )

    $defaultConfig | ConvertTo-Json -Depth 2 | Set-Content $ConfigPath
    Write-Host "Configuration file created: $ConfigPath" -ForegroundColor Green
    Write-Host "Edit the file and run the script again" -ForegroundColor Yellow
}

# Carica configurazione
function Get-RepositoryConfig {
    param([string]$ConfigPath)

    if (-not (Test-Path $ConfigPath)) {
        New-DefaultConfig -ConfigPath $ConfigPath
        return $null
    }

    try {
        $config = Get-Content $ConfigPath | ConvertFrom-Json
        return $config | ForEach-Object {
            [GitRepository]@{
                Path = $_.Path
                Branch = $_.Branch
                Description = $_.Description
                Enabled = $_.Enabled
            }
        }
    }
    catch {
        Write-Host "Error loading config file: $($_.Exception.Message)" -ForegroundColor Red
        return $null
    }
}

# Sincronizzazione multipla
function Sync-AllRepositories {
    param([GitRepository[]]$Repositories)

    $successCount = 0
    $errorCount = 0

    foreach ($repo in $Repositories) {
        if (-not $repo.Enabled) {
            Write-Host "Skipping disabled repository: $($repo.Description)" -ForegroundColor Gray
            continue
        }

        Write-Host "=================================="
        Write-Host "Repository: $($repo.Description)" -ForegroundColor Cyan
        Write-Host "Path: $($repo.Path)" -ForegroundColor White
        Write-Host "Branch: $($repo.Branch)" -ForegroundColor White
        Write-Host "=================================="

        # Esegui script principale
        try {
            $result = & ".\GitSync.ps1" -RepositoryPath $repo.Path -Branch $repo.Branch
            if ($LASTEXITCODE -eq 0) {
                $successCount++
                Write-Host "✓ $($repo.Description) - OK" -ForegroundColor Green
            } else {
                $errorCount++
                Write-Host "✗ $($repo.Description) - ERROR" -ForegroundColor Red
            }
        }
        catch {
            $errorCount++
            Write-Host "✗ $($repo.Description) - EXCEPTION: $($_.Exception.Message)" -ForegroundColor Red
        }

        Write-Host ""
        Start-Sleep -Seconds 2  # Pausa tra repository
    }

    # Riepilogo finale
    Write-Host "=================================="
    Write-Host "SYNC SUMMARY:" -ForegroundColor Yellow
    Write-Host "Successes: $successCount" -ForegroundColor Green
    Write-Host "Errors: $errorCount" -ForegroundColor Red
    Write-Host "=================================="
}

# Funzione principale
function Main {
    $repositories = Get-RepositoryConfig -ConfigPath $ConfigFile

    if ($null -eq $repositories) {
        exit 1
    }

    Sync-AllRepositories -Repositories $repositories
}

# Esecuzione
Main

Utilizzo Script PowerShell

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Esecuzione script singolo
.\GitSync.ps1                                    # Repository corrente, branch main
.\GitSync.ps1 -RepositoryPath "C:\Projects\Web" # Repository specifico
.\GitSync.ps1 "C:\Projects\Web" "development"   # Repository e branch specifici

# Sincronizzazione multipla
.\MultiGitSync.ps1
.\MultiGitSync.ps1 -ConfigFile "custom_config.json"

# Con output verboso
.\GitSync.ps1 -Verbose -RepositoryPath "C:\Projects\Web"

Schedulazione e Monitoring

Schedulazione con Cron (Linux)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Modifica crontab
crontab -e

# Esempi di schedulazione:

# Ogni ora
0 * * * * /home/user/scripts/git_sync.sh /home/user/project >> /dev/null 2>&1

# Ogni giorno alle 8:00 e 18:00
0 8,18 * * * /home/user/scripts/git_sync.sh /home/user/project

# Ogni lunedì alle 9:00 (sincronizzazione settimanale completa)
0 9 * * 1 /home/user/scripts/multi_git_sync.sh

# Ogni 30 minuti durante l'orario lavorativo (9-18)
*/30 9-18 * * 1-5 /home/user/scripts/git_sync.sh /var/www/website

# Verifica crontab attivo
crontab -l

# Log cron (per debug)
grep CRON /var/log/syslog

Schedulazione con Task Scheduler (Windows)

Crea un task con PowerShell:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# CreateScheduledTask.ps1 - Crea task schedulato

$TaskName = "GitAutoSync"
$ScriptPath = "C:\Scripts\GitSync.ps1"
$WorkingDirectory = "C:\Scripts"

# Azione del task
$Action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-ExecutionPolicy Bypass -File `"$ScriptPath`"" -WorkingDirectory $WorkingDirectory

# Trigger (ogni 2 ore dalle 8:00 alle 18:00)
$Trigger = New-ScheduledTaskTrigger -Daily -At "08:00AM" -RepetitionInterval (New-TimeSpan -Hours 2) -RepetitionDuration (New-TimeSpan -Hours 10)

# Impostazioni
$Settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable

# Registra il task
Register-ScheduledTask -TaskName $TaskName -Action $Action -Trigger $Trigger -Settings $Settings -Description "Automatic Git repository synchronization"

Write-Host "Scheduled task '$TaskName' created successfully" -ForegroundColor Green

# Per gestire il task:
# Get-ScheduledTask -TaskName $TaskName
# Start-ScheduledTask -TaskName $TaskName
# Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false

Monitoring e Alerting

Script per monitorare i log e inviare notifiche:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/bin/bash
# git_monitor.sh - Monitoring e alerting

LOG_FILE="$HOME/git_sync.log"
ALERT_EMAIL="admin@esempio.com"
ERROR_THRESHOLD=3  # Alert dopo 3 errori consecutivi

# Conta errori recenti
check_recent_errors() {
    local recent_errors=$(tail -100 "$LOG_FILE" | grep -c "ERROR\|failed")
    echo $recent_errors
}

# Invia alert email
send_alert() {
    local subject="Git Sync Alert - Errori rilevati"
    local body="Rilevati errori multipli nella sincronizzazione Git.\n\nUltimi log:\n$(tail -20 "$LOG_FILE")"

    echo -e "$body" | mail -s "$subject" "$ALERT_EMAIL"
}

# Controllo e alert
main() {
    local error_count=$(check_recent_errors)

    if [[ $error_count -ge $ERROR_THRESHOLD ]]; then
        echo "ALERT: Rilevati $error_count errori recenti"
        send_alert
    else
        echo "Status OK: $error_count errori negli ultimi 100 log entries"
    fi
}

main

Troubleshooting Comune

Problemi di Autenticazione

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Verifica configurazione credenziali
git config --list | grep credential

# Test autenticazione
git ls-remote origin

# Reset credenziali (se problematiche)
git config --global --unset credential.helper
rm ~/.git-credentials

# Riconfigurazione da zero
git config --global credential.helper store

Problemi di Connettività

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Test connessione HTTPS
curl -I https://github.com

# Test connessione specifica repository
git ls-remote https://github.com/username/repo.git

# Verifica proxy (se applicabile)
git config --global http.proxy http://proxy:port
git config --global https.proxy https://proxy:port

# Debug verbose
GIT_CURL_VERBOSE=1 git fetch origin

Problemi con Force Sync

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# Se force sync fallisce, controlla:

# 1. Permessi file
ls -la .git/
sudo chown -R $USER:$USER .git/

# 2. Lock files
rm -f .git/index.lock
rm -f .git/refs/heads/*.lock

# 3. Corrupted repository
git fsck --full
git gc --aggressive

# 4. Reset completo come ultima risorsa
git fetch origin
git reset --hard origin/main
git clean -fxd  # Attenzione: rimuove tutto

Debug Script Automazione

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Debug bash script
bash -x ./git_sync.sh

# Debug con più dettagli
set -x  # Aggiungi all'inizio dello script
set +x  # Disabilita debug

# Log dettagliato PowerShell
# Aggiungi nel script:
$VerbosePreference = "Continue"
Write-Verbose "Debug message"

Risorse Aggiuntive

La padronanza di questi strumenti e tecniche ti renderà molto più produttivo nella gestione dei repository Git, sia in progetti individuali che in team complessi! 🚀