L'auditoria de seguretat de 08-03 va canviar dotze coses del toolkit, i la lliçó d'optimització n'havia canviat unes quantes més abans. Ara mateix, si vigilant.sh comença a fallar el dimarts de matinada, ningú no sap dir què es va tocar, quan ni per què, ni com tornar a la versió que funcionava. Aquesta lliçó posa ~/veloz-ops/ sota control de versions. No és un curs de Git: és Git vist des de la necessitat concreta d'un equip d'operacions que manté cinc scripts, una llibreria i un fitxer de configuració amb credencials que no s'ha de pujar mai.

Contingut

  1. Per què copia.sh.bak.old.v2 no és control de versions
  2. Els cinc conceptes que calen
  3. Posar ~/veloz-ops/ sota control
  4. Veure què ha canviat: git diff i git log
  5. Què NO es versiona: .gitignore i la configuració
  6. Si ja has pujat un secret
  7. Missatges de commit útils en operacions
  8. Desfer amb criteri
  9. Branques per provar sense tocar producció
  10. Etiquetes i desplegament a la flota
  11. Remots i repositoris privats
  12. Un hook pre-commit de debò
  13. Flux de treball mínim per a un equip petit

  1. Per què copia.sh.bak.old.v2 no és control de versions

El patró és universal: abans de tocar un script se'n fa una còpia amb un sufix. Al cap d'un any el directori té copia.sh.bak, copia.sh.old, copia.sh.v2, copia.sh.20260715 i copia.sh.BO. I cap d'aquestes còpies no respon a les preguntes que importen: què va canviar exactament entre dues d'elles, qui ho va canviar, quan, per què i quina és la que corre ara a srv-veloz-02. Tampoc no permeten saber si el canvi del dimarts i el del dijous són independents.

Git respon a les cinc preguntes i hi afegeix dues capacitats que les còpies no donen: provar un canvi en paral·lel sense tocar el que és en producció, i desfer un canvi concret sense desfer els posteriors.

  1. Els cinc conceptes que calen

Concepte Què és Analogia
Repositori El directori amb la seva història completa, a .git/ L'arxiu del projecte
Àrea de preparació (staging) Zona intermèdia on tries què entra al pròxim commit La safata del que lliuraràs
Commit Una foto del projecte amb autor, data i missatge Una entrada de bitàcola signada
Branca Una línia de desenvolupament independent Un esborrany paral·lel
Remot Una còpia del repositori en un altre lloc El servidor on l'equip comparteix

L'àrea de preparació és el que més confon al principi i té una raó molt pràctica: permet haver tocat quatre fitxers i fer dos commits diferents, un amb la correcció de seguretat i un altre amb la millora de rendiment. En operacions això val or, perquè permet revertir-ne un sense l'altre.

  1. Posar ~/veloz-ops/ sota control

$ cd ~/veloz-ops
$ git init
S'ha inicialitzat un repositori Git buit a /home/veloz/veloz-ops/.git/
$ git config user.name "Ana Lopez"
$ git config user.email "[email protected]"

Abans del primer git add cal decidir què no hi entra, així que el correcte és escriure el .gitignore primer (apartat 5) i després afegir:

$ git add .gitignore bin/ lib/ etc/veloz-ops.conf.exemple
$ git status --short
A  .gitignore
A  bin/informe-diari.sh
A  bin/vigilant.sh
A  etc/veloz-ops.conf.exemple
A  lib/comu.sh

$ git commit -m "Versio inicial del toolkit d'operacions de Veloz Envios"
[master (commit-arrel) 4f2a1b8] Versio inicial del toolkit d'operacions
 8 files changed, 1247 insertions(+)

git add mou canvis a l'àrea de preparació; git commit els grava a la història. A git status --short, A és added, M modificat, D esborrat i ?? sense seguiment. Un detall que estalvia sorpreses: Git desa el bit d'execució, així que els chmod +x de bin/ viatgen amb el repositori.

  1. Veure què ha canviat: git diff i git log

$ git diff                    # canvis NO preparats (treball vs. staging)
$ git diff --staged           # canvis preparats (staging vs. ultim commit)
$ git log --oneline --graph --decorate -4
* 9c14e7a (HEAD -> master, tag: v1.2) Fixar PATH i IFS a comu.sh (auditoria)
* 3b8d201 Substituir bucle per awk a informe-diari.sh: 3m12s -> 3,9s
* a71f0c4 Afegir --dry-run a copia.sh
* 4f2a1b8 Versio inicial del toolkit

La distinció entre els dos diff és la que més es pregunta en començar: el primer ensenya el que encara no has afegit amb git add; el segon, el que és a punt d'entrar al commit. Revisa sempre git diff --staged abans d'escriure el missatge: és el moment natural per descobrir que t'has deixat un set -x posat. Per investigar un fitxer concret, git log -p bin/vigilant.sh mostra la seva història línia a línia i git blame bin/vigilant.sh diu quin commit va introduir cada línia: l'eina que de debò faràs servir quan alguna cosa faci mesos que està trencada.

  1. Què NO es versiona: .gitignore i la configuració

Aquesta és la part crítica. etc/veloz-ops.conf conté el token que acabem de protegir a 08-03; pujar-lo el fa visible per a tot l'equip, per sempre i a cada clon.

# ~/veloz-ops/.gitignore
etc/veloz-ops.conf        # secrets i configuracio local: MAI
etc/secrets
*.key
*.pem
.netrc
logs/                     # sortida regenerable
*.log
*.tmp
dades/                    # dades de negoci: van a la copia, no al repositori
*.csv

Al seu lloc es versiona una plantilla que documenta la configuració sense revelar res:

# etc/veloz-ops.conf.exemple   <-- aquest SI es versiona
VELOZ_API_URL="http://localhost:8080"
VELOZ_API_TOKEN="posa-aqui-el-teu-token"     # obtenir de Vault, no compartir
VELOZ_RETENCIO_DIES=30

En instal·lar el toolkit en un servidor nou es copia la plantilla, s'omple i s'ajusten els permisos. Una advertència important: .gitignore només afecta els fitxers sense seguiment. Si ja vas fer git add etc/veloz-ops.conf, afegir-lo al .gitignore no el treu: cal git rm --cached etc/veloz-ops.conf, que el treu del repositori i el deixa al disc.

  1. Si ja has pujat un secret

Passa. L'ordre de les accions no és negociable:

  1. Rota el secret immediatament. Genera'n un de nou i invalida el vell. És l'únic pas que de debò mitiga; els altres són neteja.
  2. Treu-lo del repositori actual: git rm --cached, afegeix-lo al .gitignore, commit.
  3. Reescriu la història amb git filter-repo (l'eina recomanada avui) o BFG Repo-Cleaner, que eliminen el fitxer de tots els commits.
  4. Avisa l'equip: la reescriptura canvia tots els identificadors de commit i qui tingui un clon l'haurà de refer.

I l'advertència de fons: reescriure la història no n'hi ha prou si el repositori ja s'ha compartit. Qualsevol el va poder clonar, la plataforma el va poder indexar, hi ha còpies a la memòria cau i a les còpies de seguretat. Per això el pas 1 no és opcional ni posterior.

  1. Missatges de commit útils en operacions

Un missatge no descriu el diff —això ja ho fa el diff—, sinó què va canviar i per què. En operacions, el «per què» sol ser un incident:

Missatge inútil Missatge útil
canvis Afegir timeout de 10s a veloz_api_get
arreglo Corregir divisio per zero a veloz_percentatge sense enviaments
update vigilant.sh Pujar el llindar de disc al 85% per evitar avisos falsos
wip Fixar PATH i IFS a comu.sh (auditoria de seguretat)

Convenció pràctica: primera línia imperativa de menys de 72 caràcters, línia en blanc i cos amb el context.

$ git commit -m "Reintentar la consulta a veloz-api fins a 3 cops" -m \
"Incident INC-482: el 2026-07-29 l'API va trigar 8s a respondre despres del
reinici nocturn i vigilant.sh va enviar una alerta falsa. S'afegeixen
reintents amb retroces exponencial (2s, 4s, 8s) abans d'alertar."

D'aquí a sis mesos, aquest commit explica per què existeix un bucle de reintents que a primera vista sobra. Un commit per canvi lògic: no barregis la refactorització de rendiment amb la correcció de seguretat encara que les hagis fet la mateixa tarda.

  1. Desfer amb criteri

Quatre ordres per a quatre situacions. Confondre-les és la principal font de feina perduda:

Situació Ordre Destructiu
Descartar les meves edicions d'un fitxer git restore bin/vigilant.sh Sí (perd el que no s'ha desat)
He fet git add de més git restore --staged etc/veloz-ops.conf No
Un commit ja publicat és incorrecte git revert 3b8d201 No (crea un commit invers)
Llençar commits locals encara no publicats git reset --hard 4f2a1b8 Sí, esborra història

Regla d'or: git revert per al que ja han vist altres; git reset --hard només per al que és teu i no publicat. revert deixa constància que hi va haver un canvi i que es va retirar, cosa que en operacions és informació valuosa. I si el missatge de l'últim commit està malament, git commit --amend el corregeix mentre no l'hagis pujat.

  1. Branques per provar sense tocar producció

Vols reescriure la lògica de llindars de vigilant.sh, però aquest script corre cada cinc minuts a tres servidors. Una branca et dóna un espai paral·lel:

$ git switch -c llindars-dinamics            # crea la branca i s'hi canvia
$ git commit -am "Calcular el llindar de disc amb la mitjana de 7 dies"
$ git switch master                          # master continua intacte

Quan el canvi estigui provat s'integra amb git merge llindars-dinamics i s'esborra la branca amb git branch -d. Si en l'interval algú va tocar les mateixes línies a master, Git avisa d'un conflicte i marca el fitxer:

<<<<<<< HEAD
llindar_disc=85
=======
llindar_disc=$(( mitjana_7dies + 10 ))
>>>>>>> llindars-dinamics

Resoldre'l és editar el fitxer deixant-hi la versió correcta —sovint una combinació de totes dues—, esborrar les tres línies de marques i fer git add i git commit. No hi ha màgia: decideix un humà. En scripts de Bash convé a més executar bash -n (05-03) sobre el fitxer resolt abans de confirmar, perquè un conflicte mal resolt hi deixa fàcilment un fi de més.

  1. Etiquetes i desplegament a la flota

Una etiqueta marca un punt de la història amb un nom estable, i en operacions serveix per saber quina versió corre a cada servidor:

$ git tag -a v1.2 -m "Versio desplegada a la flota el 2026-08-04"
$ git push origin v1.2

El desplegament a srv-veloz-01/02/03 combina això amb el que vam veure a 07-06:

# A) Cada servidor te un clon i s'actualitza a l'etiqueta
for h in srv-veloz-01 srv-veloz-02 srv-veloz-03; do
    ssh -n "$h" 'cd ~/veloz-ops && git fetch --tags && git checkout -q v1.2'
done

# B) Un clon de referencia i rsync a la flota (sense Git en produccio)
for h in srv-veloz-01 srv-veloz-02 srv-veloz-03; do
    rsync -a --delete --exclude '.git' --exclude 'etc/veloz-ops.conf' \
          ~/veloz-ops/ "$h:~/veloz-ops/"
done

L'opció A permet consultar la versió desplegada amb git describe a cada màquina; la B evita instal·lar Git i credencials en producció. Fixa't en l'exclusió d'etc/veloz-ops.conf: la configuració és local de cada servidor i no s'ha de sobreescriure des del repositori.

  1. Remots i repositoris privats

Un repositori local no és una còpia de seguretat: si es perd el disc, es perd la història.

$ git remote add origin [email protected]:ops/veloz-ops.git
$ git push -u origin master        # -u recorda el desti per als seguents
$ git pull                         # porta i integra el que hagin pujat altres

git pull és internament fetch més merge; si prefereixes veure què arriba abans d'integrar-ho, git fetch seguit de git log HEAD..origin/master és un hàbit excel·lent en operacions. I una advertència que no sobra: el codi d'operacions va en repositoris privats. Encara que no contingui secrets —i no n'ha de contenir—, revela noms de servidors, camins interns, llindars i estructura del sistema; és reconeixement gratuït per a un atacant. Autenticació per clau SSH (07-06), no per contrasenya.

  1. Un hook pre-commit de debò

Un hook és un script que Git executa automàticament en un cert moment. pre-commit corre abans de crear el commit i, si acaba amb un codi diferent de 0, l'avorta:

#!/usr/bin/env bash
# .git/hooks/pre-commit  -  requereix chmod +x
set -uo pipefail
fallades=0
mapfile -t scripts < <(git diff --cached --name-only --diff-filter=ACM |
                       grep -E '\.(sh|bats)$|^bin/')
(( ${#scripts[@]} == 0 )) && exit 0

for s in "${scripts[@]}"; do
    bash -n "$s"        || { printf 'sintaxi: %s\n' "$s" >&2; fallades=1; }
    shellcheck -x "$s"  || fallades=1                     # 08-05
done
[[ -d tests ]] && { bats tests/ >/dev/null || fallades=1; }  # 08-06

if git diff --cached | grep -qE 'TOKEN=|PASSWORD=|BEGIN (RSA|OPENSSH) PRIVATE KEY'; then
    printf 'possible secret al commit, revisa-ho\n' >&2
    fallades=1
fi
exit "$fallades"

Quatre barreres: sintaxi amb bash -n, anàlisi estàtica amb ShellCheck, proves amb Bats i una cerca simple de secrets. --diff-filter=ACM limita la comprovació als fitxers afegits, copiats o modificats —no té sentit analitzar-ne un que s'esborra— i només mira els preparats, no tot l'arbre. Dues limitacions que cal conèixer: els hooks viuen a .git/hooks/ i no es versionen, així que cal instal·lar-los a cada clon (per això molts equips guarden el hook a tools/ i l'enllacen amb un script d'instal·lació), i git commit --no-verify se'ls salta. El hook és una xarxa de seguretat per a despistes, no un control d'accés.

  1. Flux de treball mínim per a un equip petit

Per a dues o tres persones d'operacions n'hi ha prou amb això: git pull abans de començar; branca curta per al canvi (git switch -c corregir-timeout-api); commits petits amb missatges que citin l'incident; git push -u origin <branca> i petició de revisió a una altra persona; fusió a master, etiqueta si és desplegable i desplegament a la flota; esborrar la branca.

El penúltim pas és el més important de la llista, i no és una eina: és una persona. La revisió per part d'un altre company és el millor control de qualitat que existeix, millor que ShellCheck, que les proves i que la disciplina pròpia. Troba el que les eines no veuen: que el llindar està mal triat, que l'script assumeix un directori que només existeix a la teva màquina, que aquell rm -rf no està tan acotat com sembla. Deu minuts de revisió estalvien una guàrdia nocturna.

Errors Habituals i Consells

  • Començar per git add . sense .gitignore. És la manera més habitual de pujar un secret. El .gitignore va abans del primer commit.
  • Creure que .gitignore retira fitxers ja versionats. No ho fa: git rm --cached és el que els treu.
  • Esborrar el secret i no rotar-lo. Continua a la història, als clons i a les memòries cau.
  • git reset --hard sobre commits ja publicats. Trenca el repositori dels altres; per al que està publicat, git revert.
  • Consell: git stash per a la interrupció. Desa la feina a mitges, atén la incidència i recupera-la amb git stash pop.
  • Consell: git log -S 'veloz_api_get' busca en quin commit va aparèixer o va desaparèixer una cadena; és la manera ràpida de datar un canvi de comportament.

Exercicis

Exercici 1. Descobreixes que etc/veloz-ops.conf, amb el token de l'API, fa tres commits que està versionat en un repositori compartit amb dos companys. Enumera en ordre les accions i les ordres concretes.

Exercici 2. Escriu el .gitignore del toolkit justificant cada exclusió, i explica què es versiona al seu lloc.

Exercici 3. Has fusionat a master un canvi a vigilant.sh (commit 3b8d201) que provoca alertes falses, i ja hi ha dos commits posteriors d'un altre company. Com el desfàs sense perdre la seva feina?

Solucions

Solució 1. Primer, rotar el token a l'API i invalidar l'antic: és en tres clons i al servidor de Git, i és l'única cosa que talla l'exposició real. Després:

$ printf 'etc/veloz-ops.conf\n' >> .gitignore
$ git rm --cached etc/veloz-ops.conf
$ git add .gitignore etc/veloz-ops.conf.exemple
$ git commit -m "Deixar de versionar la configuracio amb credencials"
$ git push

Després reescriure la història amb git filter-repo --path etc/veloz-ops.conf --invert-paths (o BFG), avisant abans els dos companys que hauran de tornar a clonar perquè tots els identificadors de commit canvien. I documentar l'incident, recordant que la reescriptura no substitueix la rotació: si el repositori s'ha compartit, cal assumir que el token és públic.

Solució 2. El de l'apartat 5. etc/veloz-ops.conf, *.key, *.pem i .netrc contenen credencials; logs/ i *.log són sortida regenerable que a més faria créixer el repositori sense límit; *.tmp són temporals de mktemp; dades/ i *.csv són dades de negoci amb informació personal (08-03), que pertanyen a la còpia de seguretat i no al control de versions. Es versiona etc/veloz-ops.conf.exemple perquè documenta quines variables cal definir sense revelar-ne els valors.

Solució 3. Amb git revert, que crea un commit nou desfent exactament els canvis de 3b8d201 i deixa intactes els dos posteriors:

$ git revert 3b8d201
$ git push

git reset --hard seria un error greu: llençaria també els commits del company i, com que ja estan publicats, obligaria a un push --force que trencaria el seu repositori. Si el revert produeix conflicte perquè els commits posteriors van tocar les mateixes línies, es resol a mà com a l'apartat 9 i s'acaba amb git revert --continue.

Conclusió

Git resol per a un toolkit d'operacions el que les còpies .bak no resolen: què va canviar, qui, quan i per què, i com tornar enrere sense arrossegar la resta. Amb cinc conceptes —repositori, àrea de preparació, commit, branca i remot— n'hi ha prou per treballar: git init, git add, git commit -m, git status --short, git diff i git diff --staged per revisar abans de confirmar, git log --oneline --graph per llegir la història i git blame per saber qui va introduir aquella línia. El primer que s'escriu no és un commit sinó el .gitignore, que deixa fora logs/, temporals, dades i sobretot etc/veloz-ops.conf amb les seves credencials, versionant al seu lloc etc/veloz-ops.conf.exemple; i si un secret ja és a dins, l'ordre és rotar primer, després git rm --cached i després git filter-repo o BFG, sabent que reescriure la història no repara res si el repositori ja s'ha compartit. Els missatges descriuen el canvi i el seu motiu —l'incident que el va provocar—, amb un commit per canvi lògic. Per desfer cal triar bé: git restore descarta edicions, git restore --staged retira de l'àrea de preparació, git revert desfà el que està publicat deixant-ne constància i git reset --hard només es fa servir sobre commits propis no publicats. Les branques (git switch -c) permeten reescriure vigilant.sh sense tocar el que corre cada cinc minuts, amb fusió i resolució manual de conflictes; les etiquetes (git tag -a v1.2) fixen quina versió està desplegada i es combinen amb el desplegament a la flota de 07-06, per git checkout a cada servidor o per rsync excloent .git i la configuració local. El remot —privat i amb clau SSH— és alhora còpia de seguretat i punt de trobada. I el pre-commit automatitza les barreres: bash -n, ShellCheck, Bats i una cerca de secrets, amb la doble advertència que els hooks no es versionen i que --no-verify se'ls salta. Per damunt de tot això queda el control de qualitat més eficaç, que no és una eina: que una altra persona llegeixi el teu canvi abans que arribi a producció.

El hook pre-commit que acabem d'escriure invoca dues ordres que encara no coneixem. La lliçó 08-05 s'ocupa de la primera: ShellCheck, l'analitzador estàtic que troba els errors que aquest curs t'ha ensenyat a evitar —i uns quants més—, juntament amb shfmt per al format uniforme que 08-01 va deixar promès. Recorrerem els avisos més freqüents connectant-los amb la lliçó on es va explicar el problema, aprendrem a silenciar un avís amb criteri i no per comoditat, i passarem ShellCheck als cinc scripts i a lib/comu.sh per classificar i corregir tot el que aparegui.

Curs de Programació en Bash

Mòdul 1: Introducció a Bash

Mòdul 2: Ordres Bàsiques de Bash

Mòdul 3: Fonaments de Scripting

Mòdul 4: Scripting Intermedi

Mòdul 5: Tècniques Avançades de Scripting

Mòdul 6: Treballar amb Eines Externes

Mòdul 7: Automatització i Programació

Mòdul 8: Bones Pràctiques i Optimització

Mòdul 9: Projectes del Món Real

© Copyright 2026. Tots els drets reservats