Microsoft AZ-400: Controllo del codice sorgente e gestione dei repository — Guida allo studio
Fa parte della Microsoft DevOps Engineer Expert AZ-400 — Guida allo studio. Esercitati con risposte verificate nel centro esami Microsoft, oppure fai test cronometrati su ExamRoll.io.
Panoramica
Le moderne pratiche DevOps si basano su un controllo del codice sorgente prevedibile e collaborativo e una gestione disciplinata dei repository. Azure Repos e GitHub forniscono funzionalità complementari per il controllo di versione, l’applicazione delle policy, la collaborazione e la sicurezza. La padronanza delle strategie di branching, dei flussi di lavoro delle pull request, delle autorizzazioni, degli hook, della gestione di file di grandi dimensioni, dei pattern di migrazione, della scansione di sicurezza e del versioning è essenziale per pipeline di delivery resilienti e per l’auditabilità. L’obiettivo non è solo archiviare il codice, ma creare un sistema di controlli applicabile e automatizzato che scali la produttività del team senza sacrificare la qualità.
Fondamenti del Controllo del Codice Sorgente in Azure Repos e GitHub
Azure Repos supporta Git e Team Foundation Version Control (TFVC). Git è distribuito, consente commit locali, un branching agevole e flussi di lavoro decentralizzati. TFVC è centralizzato con versioning lato server, check-out bloccati (opzionali) ed è adatto a soluzioni legacy con asset binari molto grandi o a team abituati a flussi di lavoro centralizzati. I nuovi sviluppi dovrebbero utilizzare Git come standard; TFVC rimane una scelta valida quando il controllo incrementale delle modifiche e le autorizzazioni centrali sono di primaria importanza e il costo di migrazione è proibitivo.
Scegliere una strategia di branching in modo deliberato:
- Lo sviluppo basato su trunk (trunk-based development) favorisce un unico branch principale (main) di lunga durata con feature branch di brevissima durata e integrazione continua. Questo accelera il flusso, riduce il debito di merge ed è ideale per team ad alta cadenza con una solida automazione dei test.
- GitFlow utilizza branch di lunga durata
developemain(release), con branchfeature,releaseehotfix. Si adatta a prodotti con cicli di rilascio formali e necessità di backporting, ma aggiunge un sovraccarico di coordinamento. - GitHub Flow è un modello semplificato con un unico branch
main, branch tematici (topic branch) di breve durata, deployment continuo e rilasci frequenti. È efficace per i servizi che vengono rilasciati continuamente.
Monorepo contro multi-repo è principalmente una scelta organizzativa e di tooling:
- Il monorepo consolida molti componenti in un unico repository, facilitando modifiche atomiche tra servizi diversi, refactoring unificato e tooling condiviso. Può mettere a dura prova le operazioni di Git con l’aumentare della cronologia. Le tecniche di mitigazione includono lo sparse checkout, il partial clone e i filtri sui percorsi nella CI per definire l’ambito di build e test.
- Il multi-repo isola la proprietà, la cronologia e i confini delle autorizzazioni, facilitando il versioning e la retention indipendenti. Può aumentare il coordinamento tra repository e il disallineamento delle dipendenze (dependency drift); i sottomoduli (submodule) o i gestori di dipendenze e l’orchestrazione dei rilasci sono fondamentali.
La proprietà e l’instradamento delle modifiche traggono vantaggio dalle dichiarazioni di proprietà del codice. Il file CODEOWNERS di GitHub mappa automaticamente i percorsi ai revisori obbligatori. In Azure Repos, utilizzare i revisori obbligatori basati su percorso (path-based) nelle policy di branch (e CODEOWNERS dove abilitato) per instradare le revisioni ai team responsabili dei componenti. Completare la gestione della proprietà con convenzioni di denominazione dei branch, messaggi di commit chiari (ad es. Conventional Commits) e template di repository per garantire la coerenza.
Governance: Policy, Autorizzazioni e Pull Request
Le policy di branch (branch policies) in Azure Repos codificano i quality gate:
- I revisori obbligatori (Required reviewers) impongono un numero minimo di revisori e possono includere individui/gruppi specifici o revisori automatici basati su percorso. Richiedere la risoluzione dei commenti (Require comment resolution) per garantire che il feedback sostanziale venga gestito prima del merge.
- La validazione della build (Build validation) richiede che una o più pipeline di CI abbiano successo prima del merge. Utilizzare filtri sui percorsi (path filters) per evitare build non necessarie e impostare l’attivazione automatica sui nuovi aggiornamenti. Integrare controlli esterni tramite policy di stato (status policies) per scansioni di sicurezza o test di performance.
- Le strategie di merge possono essere vincolate: Merge (no fast-forward) registra la cronologia del merge; Squash condensa le modifiche in un singolo commit, mantenendo la cronologia lineare; Rebase and fast-forward riscrive il topic branch su
mainper una cronologia lineare; Rebase and merge applica nuovamente i commit preservando i commit separati senza un merge commit. Allineare la strategia alle esigenze di audit e al tooling a valle. - Controlli aggiuntivi includono la richiesta di work item collegati, un numero minimo di voti favorevoli e il blocco in presenza di commenti attivi o revisori in attesa.
Le pull request orchestrano la conversazione sull’integrazione:
- Le bozze di PR (Draft PRs) segnalano un lavoro in corso e bloccano il completamento finché non vengono contrassegnate come pronte. Incoraggiano un feedback precoce senza attivare prematuramente le policy.
- Il completamento automatico (Auto-complete) esegue il merge automaticamente una volta che tutte le policy sono soddisfatte, riducendo la latenza di coordinamento e aumentando il flusso.
- L’opzione per bypassare le policy (Bypass policies) esiste per situazioni di emergenza o per account di automazione. Bloccare questa possibilità con l’autorizzazione “Bypass policies when completing pull requests” e verificarne l’uso tramite approvazioni e change management.
- I template di PR standardizzano il contesto: prove di test, note sui rischi, passaggi di deployment e piano di roll-back. In Azure Repos, posizionare il file
pull_request_template.mdnella root del repository o in.azuredevops/. Fornire checklist per la sicurezza, le performance e la documentazione.
Le autorizzazioni e i branch protetti sono la vostra ultima linea di difesa:
- Utilizzare i gruppi RBAC di Azure DevOps (Project Administrators, Contributors, Readers) e autorizzazioni granulari a livello di repository (Create branch, Create tag, Contribute, Force push, Manage permissions, Bypass policies). Preferire l’uso di allow/deny sui gruppi piuttosto che sui singoli utenti.
- Proteggere i branch
maine di release negando il Force push e il Delete, limitando il permesso Contribute solo ai merge tramite PR e abilitando policy di branch che richiedono build e revisioni. Considerare l’opzione “Lock” per bloccare temporaneamente le modifiche. - Utilizzare autorizzazioni a livello di branch per limitare chi può creare o completare PR su branch sensibili e separare i compiti tra sviluppatori e release manager.
Automazione, hook, file di grandi dimensioni e sicurezza
Gli hook di Git rafforzano la qualità del codice nei punti di ingresso del repository:
- Gli hook di pre-commit applicano localmente controlli di linting, formattazione, verifica di segreti (secret check) e unit test prima che uno sviluppatore registri un commit. È importante che siano veloci e deterministici.
- Gli hook di pre-push bloccano il push di codice che non supera i test di integrazione o i controlli sulle policy. Fornire script di hook a livello di team tramite strumenti (ad es. Husky per JavaScript) e documentare la procedura di attivazione (opt-in).
- Gli hook lato server (server-side) nei servizi gestiti funzionano diversamente: GitHub supporta webhook lato server e controlli di stato obbligatori (required status checks); Azure DevOps Services non consente hook lato server personalizzati, ma supporta policy sui branch, convalide delle build, service hook e controlli di stato da sistemi esterni. In Azure DevOps Server (on-premise), gli hook lato server sono invece possibili.
Large File Storage (Git LFS) archivia i file binari di grandi dimensioni al di fuori del database di oggetti di Git, mantenendo alte le prestazioni del repository:
- Tracciare i file tramite pattern con git lfs track “*.psd” o per tipi di file binari specifici. Eseguire il commit del file .gitattributes in modo che tutti i collaboratori applichino LFS in modo coerente.
- Migrare la cronologia eseguendo git lfs migrate import con filtri sui percorsi (path) per riscrivere i file binari di grandi dimensioni come puntatori. Coordinarsi con il team e sospendere i push; usare il force-push con cautela e aggiornare i cloni.
- Gestire la larghezza di banda evitando il processo di “smudging” (sostituzione dei puntatori con i file reali) non necessario. Usare GIT_LFS_SKIP_SMUDGE=1 ed eseguire git lfs fetch/pull in modo selettivo. Mettere in cache LFS nella CI e considerare l’uso di repository di artefatti per i file binari che non necessitano di risiedere in Git.
La garanzia della sicurezza (security assurance) dovrebbe seguire un approccio “shift-left” ed essere basata su policy:
- GitHub Advanced Security (GHAS) introduce la scansione di segreti (secret scanning, inclusa la push protection), la scansione del codice (code scanning) con CodeQL e la revisione delle dipendenze (dependency review) per individuare credenziali esposte, vulnerabilità del codice e rischi nella supply-chain. Imporli come controlli obbligatori (required checks) sulle Pull Request (PR). Per Azure Repos, utilizzare Advanced Security for Azure DevOps per ottenere funzionalità simili di scansione dei segreti, SAST tramite CodeQL e analisi delle dipendenze (dependency insights).
- La scansione dei segreti dovrebbe essere configurata per bloccare i push che contengono segreti ad alta confidenza (high-confidence) e per allertare i responsabili della sicurezza. Supportare rilevatori personalizzati (custom detector) per pattern specifici dell’organizzazione.
- La scansione del codice con CodeQL dovrebbe essere eseguita sui trigger pull_request e schedule, caricando i risultati in formato SARIF come controlli di stato (status checks). Ottimizzare i pacchetti di query (query pack) per ridurre il “rumore” (noise) e garantire la copertura sui percorsi critici.
- La revisione delle dipendenze (dependency review) evidenzia le modifiche di versione e le vulnerabilità note (advisory) durante la revisione delle PR; utilizzare questa funzionalità per definire SLA di remediation e per la governance delle licenze.
Migrazione, Versioning e Gestione delle Release
La migrazione da TFVC a Git richiede una strategia e strumenti allineati alla tolleranza al rischio:
- Per una migrazione ad alta fedeltà con cronologia completa e collegamento degli work item, utilizzare git-tfs per clonare i percorsi TFVC in Git, preservando i changeset e mappando gli utenti. Partizionare per applicazione o branch per mantenere i repository Git gestibili. Pulire i file binari di grandi dimensioni con LFS durante o dopo la migrazione.
- Per una migrazione leggera dello stato attuale, utilizzare lo strumento di importazione di Azure DevOps per inizializzare un nuovo repository Git da TFVC (o un altro host Git), limitando opzionalmente la cronologia. Questo riduce la durata e il rischio, ma sacrifica una granularità storica approfondita.
- Preservare la tracciabilità migrando tag/label, mappando i branch TFVC ai branch Git e mantenendo un mirror di TFVC in sola lettura per l’audit. Convalidare con un progetto pilota, congelare il codice sorgente durante il cutover ed eseguire una matrice di verifica (build, test e deployment).
Adottare il versioning semantico per chiarezza e automazione:
- Utilizzare SemVer 2.0.0: MAJOR.MINOR.PATCH con metadati opzionali di pre-release (es. -rc.1) e di build (+build.45). Taggare le release con tag annotati (git tag -a v1.4.2 -m “Release 1.4.2”) e firmare i tag per l’audit.
- Automatizzare gli incrementi di versione nella CI/CD:
- Derivare la versione dai commit con i Conventional Commits e uno strumento di release (es. GitVersion o semantic-release) per calcolare la versione successiva in base ai tipi e agli scope dei commit.
- Aggiornare automaticamente i numeri di build e le versioni dei pacchetti; far fallire la build in caso di disallineamento delle versioni (version drift) o conflitti di tag.
- Allineare il versioning con la strategia di branching:
- Trunk-based: il branch main è sempre rilasciabile; creare i tag di release da main; usare branch di release di breve durata solo per la stabilizzazione.
- GitFlow: i branch release/* contengono una versione minor congelata; creare branch hotfix/* da main per patch urgenti; fare il merge di ritorno sia su develop che su main e taggare al completamento del merge.
- GitHub Flow: taggare main al momento del deployment; usare tag di pre-release per i canary.
Integrare l’automazione delle release con le policy dei repository: richiedere build superate (green build) con le pipeline di release, bloccare i merge senza changelog aggiornati generati dai commit e richiedere commit/tag firmati in ambienti regolamentati.
Scenario Pratico
Starbucks deve consolidare diverse applicazioni legacy gestite in TFVC in Azure Repos Git, stabilendo al contempo una governance uniforme, scansioni di sicurezza e flussi di lavoro scalabili sia per i servizi che per le app mobili.
- Scegliere la topologia dei repository e la strategia di branching
- Azione: Adottare lo sviluppo trunk-based con un monorepo per le librerie condivise e alcuni repository di servizi dedicati per i servizi rilasciati in modo indipendente. Abilitare lo sparse checkout per il monorepo negli script di onboarding degli sviluppatori.
- Perché: Il trunk-based riduce il debito di merge e accelera l’integrazione; il monorepo centralizza il codice condiviso e consente refactoring atomici, mentre lo sparse checkout evita l’overhead della cronologia completa e del working tree per i team che lavorano solo su sottoinsiemi del codice.
- Migrare i progetti TFVC a Git preservando la cronologia dove aggiunge valore
- Azione: Usare git-tfs per migrare le codebase principali web e mobile con la cronologia completa, mappando i percorsi degli asset di grandi dimensioni su Git LFS durante la migrazione. Per le utility più piccole, usare lo strumento di importazione di Azure DevOps per importare solo lo stato corrente.
- Perché: git-tfs preserva la tracciabilità critica per le applicazioni di punta; l’uso selettivo dello strumento di importazione accelera le migrazioni a basso rischio e riduce la durata del progetto.
- Stabilire branch protetti e branch policy
- Azione: Proteggere main e release/* con il divieto di Force push/Delete; richiedere due revisori, la risoluzione di tutti i commenti, il collegamento a un work item e il superamento della validazione della build con filtri di percorso (path filters). Limitare i merge a Squash per i repository dei servizi e a Rebase and fast-forward per il monorepo per mantenere una cronologia lineare. Disabilitare l’opzione “Bypass policies” eccetto per un piccolo gruppo di ingegneri di release.
- Perché: La policy-as-code rafforza i quality gate e l’auditabilità. Le strategie di merge riflettono le preferenze del team: lo Squash semplifica il revert e il cherry-pick per i servizi; una cronologia lineare nel monorepo accelera le operazioni di blame e bisect.
- Standardizzare le pratiche per le pull request
- Azione: Aggiungere un file pull_request_template.md in .azuredevops/ con sezioni per il rischio, le prove di test, l’impatto sulle prestazioni e il rollback. Incoraggiare l’uso precoce delle Draft PR; abilitare l’Auto-complete su tutte le PR. Configurare revisori obbligatori basati sul percorso (path-based) per emulare la proprietà del codice (code ownership) e aggiungere file CODEOWNERS per i repository ospitati su GitHub.
- Perché: I template elevano lo standard minimo per la qualità della revisione; le Draft PR promuovono la collaborazione precoce; l’Auto-complete elimina i tempi morti; l’instradamento basato sulla proprietà del codice (ownership routing) assegna i revisori giusti alle modifiche giuste (diff).
- Implementare hook e gate di CI
- Azione: Distribuire hook pre-commit/pre-push tramite gli strumenti del repository per imporre linting, controllo dei segreti e unit test; mantenere l’esecuzione veloce. Usare la validazione della build di Azure Pipelines come meccanismo di imposizione canonico e aggiungere controlli di stato (status check) dagli scanner di sicurezza. Evitare hook personalizzati lato server; usare i service hook per notificare sistemi esterni.
- Perché: Gli hook locali individuano i problemi precocemente senza bloccare la collaborazione; l’imposizione lato server in Azure DevOps si ottiene al meglio con le branch policy e gli status check per garantire affidabilità e audit.
- Gestire asset di grandi dimensioni con Git LFS
- Azione: Tracciare i pattern di file binari (immagini, asset di design, media per test) con git lfs track; migrare i binari legacy con git lfs migrate import. Configurare la CI per impostare GIT_LFS_SKIP_SMUDGE=1 ed eseguire il fetch selettivo per ridurre la larghezza di banda; memorizzare nella cache gli artefatti LFS sugli agenti di build.
- Perché: Mantiene i repository veloci ed evita un uso eccessivo della rete, garantendo al contempo build riproducibili.
- Integrare Advanced Security
- Azione: Abilitare GitHub Advanced Security sui repository GitHub e Advanced Security for Azure DevOps sui repository Azure Repos. Attivare la scansione dei segreti (secret scanning) con protezione al push, eseguire CodeQL sulle PR e con cadenza notturna, e abilitare i controlli di revisione delle dipendenze (dependency review). Bloccare il completamento delle PR in presenza di risultati ad alta gravità.
- Perché: Sposta la sicurezza a sinistra (shift left), impedendo che credenziali trapelate e pattern sfruttabili entrino nel branch main, fornendo informazioni utili e attuabili durante la revisione.
- Automatizzare il versioning semantico e il tagging
- Azione: Usare GitVersion in Azure Pipelines per calcolare il SemVer dalla cronologia dei branch e dei commit; firmare e inviare (push) tag annotati nelle pipeline di release; generare le note di rilascio dai Conventional Commits. Usare i branch release/* solo per la stabilizzazione; creare gli hotfix da un tag su main.
- Perché: Versioni deterministiche e automatizzate migliorano la tracciabilità e la riproducibilità del deployment, e i tag firmati supportano la conformità.
Questa sequenza riduce il rischio di migrazione, impone qualità e sicurezza coerenti e ottimizza la delivery, allineando con precisione la gestione dei repository con le operazioni DevOps scalabili.
Tutti i domini · Pipeline CI →
Esercitati su queste domande → · Pratica cronometrata su ExamRoll.io →
Pass the whole exam — not just this question
You found this answer. Get every verified question and explanation in one place, and save hours of prep. Free to start.
Supera l'esame →