Quando si parla di software di versioning, Git
è sicuramente il primo programma che ci viene in mente. Rappresenta l’alternativa più diffusa a sistemi come svn
, utilizzata anche in ambito enterprise.
Rappresenta anche uno dei primi scogli che dipendenti alle prime armi affrontano in azienda.
Ecco quindi una guida passo passo a Git, parte 5: ignorare.
Questo articolo affronterà i seguenti argomenti:
Dopo aver creato un nuovo progetto, il primo passo fondamentale è indicare una serie di file e cartelle da escludere dalla sincronizzazione. Non tutti i file sono destinati a essere sincronizzati, spesso all’interno dei progetti si trovano file che possono essere rigenerati, file binari o contenenti informazioni sensibili.
Per gestire questa situazione, è necessario creare un file gitignore, che consiste in una lista di “percorsi” che Git ignorerà durante la verifica dei file modificati. Questo file risiede nella cartella principale del progetto e deve essere nominato .gitignore
(è importante che ci sia il punto davanti).
Il file supporta anche l’utilizzo di alcuni caratteri jolly, come *
, per indicare “qualsiasi combinazione di caratteri”, molto utile per specificare ad esempio solo le estensioni dei file.
Per esempio, nel caso di un progetto Java, potrebbe essere opportuno escludere dalla verifica di Git i file binari generati durante la compilazione dei sorgenti. In tal caso, il contenuto del file .gitignore
potrebbe essere:
bin/
*class
Come spiegato, alcuni caratteri son visti dal file di gitignore come “caratteri jolly”, ovvero sono utilizzati per indicare gruppi di caratteri, negazioni o altro. Ecco una lista completa:
*
indica una qualunque sequenza di caratteri. Ad esempio *class
son tutti i file che finiscono ocn class
?
indica un qualunque carattere singolo. Ad esempio Mari?
rappresenta sia Mario
che Maria
che qualunque parola che inizia con Mari de ha un ulteriore carattere alla fine.!
: Esclude un pattern dal gitignore, utile quando si è utilizzato un carattere jolly per ignorare molti files, ma ci son eccezioni.
foglio?
e nella linea dopo !foglio2
si escludono tutti i file che iniziano con foglio, continuano con un carattere, ma non foglio2, che fa eccezione.#
: Indica un commento. Le righe che iniziano con # sono ignorate.[]
: Tra le parentesi quadre si può specificare un insieme di caratteri consentiti in una posizione specifica nel nome del file.
foglio[0123456789]
si ignoreranno tutti i file che iniziano con foglio e continuano con un numero.[!]
: Il contrario del precedente, indica un insieme di caratteri che devono essere esclusi dal pattern.
foglio[!2]
si ignoreranno tutti i file che iniziano con foglio e continuano con un carattere, ma non foglio2 che fa eccezione.\
: Permette di escludere caratteri speciali come [, ], , ?, e \ stessi. Ad esempio, foo* corrisponderà a un file chiamato foo, ignorando il carattere jolly *.Un sito utilizzatissimo per la gestione del gitignore è Gitignore.io, inserendo una serie di parole chiave genererà per voi un gitignore.
Ad esempio usando le parole chiave: “java” e “maven” si avrà:
# Created by https://www.toptal.com/developers/gitignore/api/java,maven
# Edit at https://www.toptal.com/developers/gitignore?templates=java,maven
### Java ###
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
# Eclipse m2e generated files
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
# End of https://www.toptal.com/developers/gitignore/api/java,maven
Un altro progetto molto interessante è git-ignore, un utility da terminale che si può trovare a questo link Github.
Questo progettino scritto in rust amplia le funzionalità di Git generando da linea di comando il gitignore.
Per utilizzarlo innanzitutto bisogna avere Rust, si proceda con l’installazione.
Per installare Rust su Ubuntu basta eseguire:
apt install cargo
Per installare Rust su Fedora basta eseguire:
dnf install cargo
Per installare Rust su ArchLinux basta eseguire:
pacman -S rust
Innanzitutto si proceda con il download il progetto con git:
git clone https://github.com/janniks/git-ignore.git
quindi entrate nella cartella:
cd git-ignore
Quindi si può compilare il progetto con il tool cargo
, fornito insieme all’installazione di rust:
cargo build
il file che vi si genera nella cartella target/debug chiamato git-ignore
è il binario da usare.
Va trasferito in una cartella coperta da variabile d’ambiente PATH, ad esempio /usr/bin
:
cp target/debug/git-ignore /usr/bin/git-ignore
Ora alla creazione di un progetto si può digitare:
git-ignore
Oppure:
git ignore
Il software si scaricherà i template dal sito (bisogna avere una connessione attiva) darà la possibilità di scegliere il template direttamente da terminale, appendendo il risultato ad un attuale .gitignore
pre-esistente oppure creandone uno nuovo.
Nota:
La ricerca si aggiorna in tempo reale, alla pressione dei tasti appariranno i risultati, con un invio si selezionerà il template sotto cursore. Per terminare, dare un invio senza scrivere nulla.
Spesso mi è capitato di vedere la seguente scena: un progetto iniziato, alcuni file da ignorare committati e solo dopo un file .gitignore con quei file. I file però non si cancellano dal remote, e chiunque scarica il progetto se li ritroverà. Come fare?
Con queste semplici istruzioni. Per prima cosa va rimosso il file ma in cache:
git rm --cached percorso/file
Con questa istruzione il file verrà rimosso soltanto dalla cache ma non fisicamente, è ora possibile fare “commit di questa rimozione”:
git commit
Infine è possibile ora fare la push:
git push
Dal repository remoto il file sarà sparito, tuttavia in locale sarà ancora presente.
]]>Quando si parla di software di versioning, Git
è sicuramente il primo programma che ci viene in mente. Rappresenta l’alternativa più diffusa a sistemi come svn
, utilizzata anche in ambito enterprise.
Rappresenta anche uno dei primi scogli che dipendenti alle prime armi affrontano in azienda.
Ecco quindi una guida passo passo a Git, parte 4: approfondimento branch.
Questo articolo affronterà i seguenti argomenti:
Come già spiegato in precedenza, GIT permette di creare rami paralleli in cui poter gestire contemporaneamente varie versioni del progetto.
Il primo passo verso la strutturazione di un buon progetto è delinearne i branch.
È importante notare che un branch creato a partire da un altro ha tutte le modifiche dell’originale, ma solo fino al momento della divisione. Da quel momento in poi qualunque modifica sarà indipendente e non intaccherà né da un lato né da un altro.
Le diramazioni di git condividono, fino al punto in cui si son divise, gli stessi file nello stesso stato, mentre da quel momento in poi vivono due vite separate fino a che la diramazione non si ricongiunge con il ramo principale. Alcuni esempi di divisioni utili in branch potrebbero essere:
La gestione di “divisione” dei branch è un concetto che va deciso con il team e rientra in quella pratica definita come “branch strategy”. Con questo termine si intendono tutte quelle scelte di team quali:
Esistono delle convenzioni comuni per i nomi dei branch, in genere:
master
o main
è generalmente chiamato branch di produzione. Ovvero è quel branch dove vi è una versione stabile del software.develop
che viene utilizzato come branch di sviluppo. Ovvero quel branch dove vengono portati avanti gli sviluppi fino a che non si concludono e possono essere portati su master.feature/
.support/
hotfix/
release/
, su questo si fanno poi le varie merge per costruire il rilascio e quindi poi si passa tutto in develop.I path dei branches che iniziano con hotfix/
, support/
e release/
normalmente terminano con il numero di versione del progetto, la domanda potrebbe essere: come si costruisce il numero di una versione?
Normalmente il numero di versione di un progetto è diviso in tre campi, separati da un punto MAJOR.MINOR.HOTFIX
, è presto detto il significato di questi tre termini:
MAJOR.MINOR
che è stata indicata come “versione di supporto”, ovvero non vi son più sviluppi attivi di sopra.
Per rinominare un branch, posizionarsi sul branch tramite checkout:
git checkout NOMEVECCHIOBRANCH
In seguito si può scrivere:
git branch -m NUOVONOMEBRANCH
Si supponga il seguente scenario:
x
per fare una modifica da develop
.x
, develop
viene portato avanti.A questo punto è giusto porsi il problema: se il branch originale è cambiato, come prelevarsi i cambiamenti in modo da poter continuare a sviluppare sul branch in un’ottica aggiornata? È qui che interviene il concetto di rebase:
git rebase NOMEBRANCH
Ad operazione finita, il branch corrente si sarà spostato sul branch di rebase, assorbendo tutti i commit.
Potrebbe succedere che l’operazione di rebase si interrompa a causa di un conflitto. Il concetto di conflitto è molto semplice: se vi sono due modifiche sullo stesso file git tenta di fare una “fusione” dei due file in maniera intelligente, tuttavia se le modifiche son avvenute nella stessa parte del codice invece di procedere, git interrompe l’operazione e delega all’utente le scelte da fare su come unire i due files.
In caso di conflitto durante un merge esce il messaggio di errore:
CONFLITTO (contenuto): conflitto di merge in percorso/file
Se capita un conflitto, il primo step da seguire è quello di aprire i file che hanno creato conflitto e risolverli. In genere le zone determinate da questa situazione son delineate dai caratteri <
, =
e >
, come in questo caso:
Prima riga
seconda riga
terza riga
<<<<<<< HEAD
quarta riga con altra modifica
=======
quarta riga con modifica da repo1
>>>>>>> b186b01f45a3b8ba301936fe1f705083f9b40cfd
quinta riga
sesta riga
La quarta riga nell’esempio di cui sopra è andata in conflitto, la prima zona (contrassegnata da <
e quindi HEAD
) è quella locale; mentre la seconda zona preceduta dai segni =
è quella in ingresso (dal branch di rebase).
Per gestire il conflitto bisogna decidere quale delle due parti tenere e, eventualmente, effettuare ulteriori modifiche. Eliminare quindi i caratteri in eccesso (<
, =
e >
).
Una volta gestito il conflitto, si aggiunge allo stage e si committa:
git add percorso/file/conflitto
git commit
Quindi si può continuare con la rebase:
git rebase --continue
Se invece si vuole interrompere definitivamente il processo si può scrivere:
git rebase --abort
Una volta che si stacca un branch e si modifica, è una pratica molto comune quella di “riunirlo” in un secondo momento.
Questa pratica è detta “merge” e si effettua come segue:
git checkout NOMEBRANCHORIGINALE
git merge NOMEBRANCHDAUNIRE
Se ci son state modifiche sugli stessi file è possibile gestire quale genere di algoritmo utilizzare per fare la fusione, per far si che git si occupi di tutto (a meno di conflitti) scegliere quello di fast-forward
:
git merge NOMEBRANCHDAUNIRE --ff
Anche la merge può entrare in conflitto ovviamente. In tal caso risolvere i conflitti come visto per il rebase, fare una git add
ed una commit
, quindi il conflitto viene automaticamente risolto.
La pull viene vista come una merge tra il repository locale e quello remoto, può quindi entrare in conflitto e si può specificare, in caso di modifiche concorrenti, il flag di fast forward:
git pull NOMEREMOTE NOMEBRANCH --ff
Per chiudere un branch, o meglio eliminarlo, si proceda con:
git branch -d [nome branch]
Per fare una lista completa dei branch invece:
git branch -a
Tuttavia questo comando non mostra quali sono le relazioni tra vari branch, quindi si può pensare, per informazioni più complete, di digitare:
git log --graph --color --decorate --oneline --all
che fa una lista dei commit dividendo i vari branch se questi non sono sincronizzati.
]]>Quando si parla di software di versioning, Git
è sicuramente il primo programma che ci viene in mente. Rappresenta l’alternativa più diffusa a sistemi come svn
, utilizzata anche in ambito enterprise.
Rappresenta anche uno dei primi scogli che dipendenti alle prime armi affrontano in azienda.
Ecco quindi una guida passo passo a Git, parte 3: remote.
Questo articolo affronterà i seguenti argomenti:
Una delle peculiarità dei software per il versioning dei progetti è la “sincronizzazione tra più repository”.
È infatti questa caratteristica a renderlo uno strumento perfetto per lavorare in team su un progetto, permettendo di gestire anche eventuali conflitti.
Si è già definito un repository Git come una cartella che contiene le informazioni per ricostruire tutto lo storico delle modifiche di un progetto, tale cartella è interamente locata nel progetto sotto il nome .git
oppure, se minimale (bare
) ha una cartella dedicata con il nome del progetto.
Si può sincronizzare un progetto Git con un repository Git esterno solo se bare
(altrimenti alcune operazioni potrebbero non funzionare), ma al di la di questo vincolo, non ci sono ulteriori limitazioni.
Quando si parla di repository esterno si parla principalmente di una cartella esterna, ma “la posizione” di questa cartella non è vincolata in nessun modo, infatti ci si può sincronizzare:
Si possono avere più repository esterni sincronizzati con un progetto, rendendo così possibile scaricare il codice da un repository X e inviarlo ad un repository Y. Per questo motivo ognuno di essi deve avere un nome associato (di solito il primo si chiama origin).
Se il progetto è stato originariamente clonato si ha già un repository esterno configurato con il nome di “origin”. In altri casi si potrebbe volere associare a posteriori, in tal caso lo si fa con l’istruzione:
git remote add NOMEREPOSITORY URLREPOSITORY
Ad esempio si può impostare un repository esterno proveniente dal sito GitHub, definendolo origin:
git remote add origin https://github.com/NOMEUTENTE/NOMEPROGETTO
Ovviamente il progetto deve essere preesistente. Oppure si può impostare un progetto su connessione ssh:
git remote add origin ssh://nomeutente@ind.iri.zzo.ip:/Cartella/Progetto
Come già detto, Git supporta anche la possibilità di impostare come “repository esterno” anche una cartella locale, sul nostro sistema. Questa pratica può essere utile in diverse occasioni (come test, sincronizzazioni con cloud client locali o esercitazioni).
Per sincronizzare un progetto con una cartella del nostro file system il primo passo è quello di creare la cartella ed impostarla come repository minimale:
mkdir repositoryEsterno
cd repositoryEsterno
git init --bare
Quindi si entra nella cartella del progetto per collegare la cartella appena creata:
cd CartellaProgetto
git remote add origin /percorso/del/repositoryEsterno
Le operazioni per comunicare con la repository sono:
Per effettuare una pull basta scrivere:
git pull NOMEREPOSITORY NOMEBRANCH
Ad esempio per fare il pull da un repository chiamato “origin
” e dal branch main
:
git pull origin main
Per effettuare una push, invece, basta scrivere:
git push NOMEREPOSITORY NOMEBRANCH
Ad esempio per fare il push su un repository chiamato “origin
” e dal branch main
:
git push origin main
Se si hanno più repository è consigliato anche inserire un “upstream” principale:
git push --set-upstream [nomerepository] [nomebranch]
Il flag --set-upstream
vale sia per push che per pull, e va inserito solo la prima volta, in seguito Git, riconoscendo il tracking remoto, per ogni operazione di push o pull in cui non si specificano ulteriori parametri darà per scontati quelli indicati per il tracking.
Ad esempio scrivendo:
git pull --set-upstream origin main
git push
Il secondo push sotto intenderà come parametri origin
e main
.
Così facendo, branch e repository sono sempre selezionati in maniera predefinita se non specificati.
Per modificare il tracking si può utilizzare anche la seguente operazione:
git branch --set-upstream-to=NOMEREPOSITORY/NOMEBRANCH
Si può lavorare impostando più repository esterni alla volta. Per farlo basta evitare di utilizzare lo stesso nome per i repository:
git remote add origin https://github.com/NOMEUSER/NOMEREPOSITORY
git remote add locale /percorso/a/Repo/locale
Ovviamente ci si aspetta che i progetti siano coerenti da una sorgente ad un altra. Perché però utilizzare questa funzione?
Uno dei casi più comuni è quello di creare una copia (anche detta fork su alcune piattaforme) di un progetto di qualcun’altro per apportare delle proprie modifiche personali. In questo modo si può controllare lo stato del progetto originale, eventualmente aggiornare di pari passo alle sue modifiche, ma mantenere una certa divergenza rispetto le proprie esigenze.
Un altro caso comune è quello della mancanza di permessi su un certo progetto: in ambito business spesso le piattaforme non consentono la creazione di nuovi branch o la merge a tutti gli utenti, quindi ci si può creare un proprio repository personale locale dove poter utilizzare tutte le features in totale tranquillità e poi mandare il codice al progetto sorgente solo quando si saranno ottenuti tutti i permessi.
Si è visto più volte il termine branch, ma ancora probabilmente non è chiaro il concetto che c’è dietro. Cos’è un branch?
Un branch in Git è una ramificazione del progetto principale, che consente agli sviluppatori di lavorare su diverse funzionalità o correzioni di bug in modo isolato.
Si può pensare ad un branch come una copia separata del progetto, dove le modifiche possono essere apportate senza influenzare il ramo principale o gli altri rami.
Questo approccio permette agli sviluppatori di sperimentare e lavorare in modo collaborativo in modo sicuro, senza compromettere la stabilità del codice principale oppure entrare in conflitto con modifiche concorrenti del progetto.
Per crearne uno basta digitare:
git branch NOMEBRANCH NOMEREMOTE/NOMEBRANCH
Poi per passare a quel branch:
git checkout NOMEBRANCH
È anche possibile passare ad un nuovo branch e crearlo in un colpo solo:
git checkout -b NOMEBRANCH NOMEREMOTE/NOMEBRANCH
E si può ritornare su un branch già esistente scrivendo:
git checkout NOMEBRANCH
Se un branch è presente in un repository esterno si può scaricare ed impostare il tracking in maniera automatica scrivendo:
git checkout -b NOMEBRANCH NOMEREMOTE/NOMEBRANCH
NOTA BENE:
Quando stacchi un branch viene creata una copia del progetto a partire dal punto in cui lo si è staccato. Ad esempio creando un branch “develop” da main creiamo una copia del progetto di quel branch. Dopo aver apportato delle modifiche, Il branch develop diverge, se si stacca un nuovo branch la nuova copia avverrà a partire da develop se ci si trova su quel branch ancora.
È sempre importante controllare lo stato delle modifiche e la differenza tra vari codici con il repository esterno.
L’operazione di check più semplice da fare è sicuramente:
git status
che mostra le informazioni basilari sui vari cambiamenti.
Per avere informazioni complete anche per quanto riguarda i repository, è meglio dare, prima di controllare lo stato, una fetch:
git fetch NOMEREPOSITORY
Lo status prende diverse parametri che possono essere più o meno utili, eccone alcuni:
-b nomebranch
: visualizza informazioni su quel branch--short
: visualizza giusto i file con il tipo di modifica (+ per aggiunto, m per modificato …)--ignored
: visualizza i file ignoratiQuando si parla di software di versioning, git
è sicuramente il primo programma che ci viene in mente. Rappresenta l’alternativa più diffusa a sistemi come svn
, utilizzata anche in ambito enterprise.
È anche uno dei primi scogli che dipendenti alle prime armi affrontano in azienda.
Ecco quindi una guida passo passo a GIT, parte 2: operazioni base.
Questo articolo affronterà i seguenti argomenti:
GIT obbliga l’utente a “identificarsi” prima di memorizzare le modifiche.
Il motivo è intuitivo, dovendo ricostruire la storia delle modifiche ad un progetto è lapalissiano che debba anche sapere chi e quando ha fatto una modifica.
Le configurazioni dell’utente possono essere globali o localizzate progetto per progetto, per cambiare globalmente il nome utente su GIT scrivere:
git config --global user.name "Nome Utente"
Per cambiare invece la propria email (anche quella necessaria) scrivere:
git config --global user.email "indirizzo@email.com"
NOTA BENE:
Le configurazioni utente di git non hanno nulla a che fare con gli account dei provider online di GIT (GITHUB, GITLAB, Bitbucket…), servono solo ad identificare chi ha fatto un commit.
Configurazioni utente e account online possono essere differenti senza alcun problema
Per verificare che il nome sia stato impostato in modo corretto si può scrivere:
git config --global user.name
Per verificare l’email occorrerà scrivere:
git config --global user.email
Come spiegato in precedenza, le configurazioni global si riferiscono all’utente su qualunque progetto, e risiedono, in genere, nelle cartelle di configurazione del sistema (ad esempio /etc/gitconfig
, oppure ~/.gitconfig
, nel caso di sistemi Linux).
Si possono però specificare anche singolarmente, per ogni progetto.
Per farlo, dai comandi precedenti, basta rimuovere il parametro --global
:
# Per il nome
git config user.name "Nome Utente"
# Per email
git config user.email "indirizzo@email.com"
Questa differenza può essere utile se si vuole distinguere la firma (intesa come email e nome) che si apporterebbe su un progetto di lavoro da quella che, invece, si vuole che risulti su un progetto personale.
Potrebbe essere necessario impostare altri due parametri per ottenere una configurazione che non darà noie, cioè l’editor di testo e un merge tool esterno:
Tuttavia, questa scelta si può personalizzare nel seguente modo:
git config --global core.editor [comando che avvia l'editor]
Spesso si richiede che questo intervento venga eseguito manualmente da parte di git
, quindi è bene tenersi uno strumento preferito (consiglio meld), specificandolo con il comando:
git config --global merge.tool [comando che avvia lo strumento di merge]
Come prima, il parametro --global
è utilizzato solo se si vuole applicare la configurazione a tutto il workspace.
Si può controllare lo stato delle modifiche in atto con:
git status
Lo stesso comando inoltre suggerisce eventuali altri comandi da effettuare per portare i file da uno stato ad un altro.
Se si hanno modifiche locali (in working area) ancora non aggiunte nell’area di staging, si possono eliminare come segue:
git rm -rf percorso/cartella/o/file
git checkout -- percorso/nomefile
# OPPURE
git restore percorso/nomefile
git clean -xdf
Dopo aver apportato delle modifiche al progetto, la prima fase che bisogna considerare è quella di aggiungere le nostre modifiche alla staging area. Quest’operazione si fa semplicemente così:
git add percorso/file
Si possono anche indicare più percorsi e quindi più file, così come una cartella intera, per selezionare tutti i file che sono stati modificati al suo interno.
# aggiunge due file
git add percorso/file1 percorso/file2
# Aggiunge un intera cartella
git add percorso/cartella/
Per evitare di selezionare tutti i file o tutte le cartelle singolarmente, si può scrivere un generico:
git add .
Posizionandosi nella root del progetto, questo aggiungerà in un colpo solo tutti i file modificati.
Il processo di “add” si può invertire, scrivendo:
git restore --staged percorso/nomefile
La prossima fase è quella di registrare i cambiamenti sul repository locale. Questa operazione, come già detto in precedenza, è denominata commit.
La commit deve essere accompagnata da un breve messaggio che spiega il contenuto delle modifiche.
Questi messaggi potranno poi essere letti in un momento successivo, perciò è importante che abbiano un senso e che aiutino a capire come si è evoluta la storia di un progetto (in genere sono accompagnati ad un codice che identifica un task).
Durante questa fase è importante aver configurato il nome e l’email dell’utente.
Per creare un commit la struttura del comando deve essere simile alla seguente:
git commit -m "messaggio di commit"
Si può fare il commit di alcuni files piuttosto che altri, scrivendoli uno dopo l’altro separati da uno spazio nel comando:
git commit -m "messaggio di commit" file1 percorso/file2 cartella2 ...etc...
Se il percorso non viene specificato, git
inserirà tutti i file della staging area nel repository.
In verità, per fare un commit complessivo di tutti i file potrebbe essere necessario utilizzare il comando:
git commit -a
che genera, inoltre, un messaggio di commit consigliato (ma commentato), aprendo il proprio editor di sistema per consentirne la modifica.
Come spiegato in precedenza, insieme ad un commit vengono memorizzate le informazioni sull’autore ma anche un piccolo messaggio.
A necessità, si può modificare l’ultimo messaggio tramite il parametro amend:
git commit --amend
Per buona norma è meglio eseguire tanti piccoli commit significativi, in modo che ognuno di questi si riferisca ad uno specifico cambiamento del comportamento generale del progetto, piuttosto che effettuare un unico commit, più corposo e più complesso, che descrive una serie di novità.
Questo perché è importante capire quale sia la modifica che, eventualmente, può avere causato, ad esempio, un problema di regressione e poter, quindi, più facilmente, individuare e correggere le righe che riguardano l’anomalia.
Si può generare un messaggio di commit casuale grazie al sito whatthecommit.com così:
git commit -m "$(curl -s https://whatthecommit.com/index.txt)"
I messaggi generati sono ovviamente molto comici.
Una volta effettuato un commit, quest’ultimo viene aggiunto ad una sequenza temporale detta log. La consultazione di questi file permette di verificare la storia delle modifiche, i messaggi, gli autori, le date ed i codici (poichè viene assegnato un codice ad ogni commit).
Queste informazioni sono verificabili con:
git log
Se l’interesse è quello di visionare soltanto il messaggio o il codice dell’operazione si può specificare il parametro --oneline
, che riassume queste informazioni:
git log --oneline
Per avere un log ancora più accurato è possibile utilizzare whatchanged
:
git whatchanged
che mostra anche un elenco dei file che sono stati cambiati nella storia del commit.
Per invertire un commit ci sono diverse strade: quella più ‘sicura’ è sicuramente il revert, che considera questa azione di regressione come se si trattasse di un commit a sé stante. Questo significa che si ha la possibilità di fare il revert del revert per ritornare alla situazione originale.
L’operazione di revert richiede due fasi:
git log --oneline
git revert codice-commit
Ad esempio, supponendo di aver eseguito, di recente, i tre commit seguenti (ordine cronologico dall’alto verso il basso):
Digitando:
git revert bbbb321
si ritornerà alla situazione in cui ancora non è stato aggiunto il file 2, ma in cui è ancora valido il commit aaaa123.
Se si aggiunge il parametro -n è possibile evitare il commit:
git revert -n codicecommit
Una soluzione più drastica, invece, consiste nell’utilizzare il reset che, a differenza di revert, elimina totalmente la storia fino al commit indicato (necessita sempre di conoscere il codice del commit):
git reset codicecommit
Questa operazione cancellerà i commit, ma non i files. Sarà quindi possibile aggiungere i file che si vuole per creare una nuova commit.
Se si vogliono cancellare sia i commit che le modifiche dell’area di staging si può utilizzare il flag --hard
durante una reset. Scrivendo:
git reset --hard codicecommit
Verrà cancellata la storia fino al commit selezionato e verrà cancellato anche ogni files che non era presente a quel commit.
In questo caso bisogna fare una distinzione:
git update-ref -d HEAD
git reset --soft HEAD^
**ATTENZIONE:**
Non utilizzare mai la prima soluzione nel caso della seconda. Otterrete risultati catastrofici!
Un piccolo riassunto di quanto detto:
]]>Quando si parla di software di versioning, git
è sicuramente il primo programma che ci viene in mente. Rappresenta l’alternativa più diffusa a sistemi come svn
, utilizzata anche in ambito enterprise.
Rappresenta anche uno dei primi scogli che dipendenti alle prime armi affrontano in azienda.
Ecco quindi una guida passo passo a git, parte1: Introduzione.
Se qualcuno di voi ci segue da più tempo saprà che esisteva un altra guida creata nel 2020 di git. Si è deciso di riscriverla poiché troppo complesso come argomento da affrontare in un articolo solo.
La vecchia guida resterà comunque disponibile fino a che non verrà totalmente coperta dai contenuti di quella nuova.
Questo articolo affronterà i seguenti argomenti:
Per i meno pratici, semplificando il più possibile, un sistema di controllo versioni è un software che gestisce l’evoluzione di un progetto, o più comunemente di una folder directory del nostro file system.
Ne confronta le varie versioni, tiene traccia dei cambiamenti per singoli file e per singola release.
Questo approccio, particolarmente adottato nei progetti di programmazione, consente di tenere traccia degli autori delle modifiche, fare modifiche contemporaneamente a dei collaboratori gestendo in maniera intelligente i conflitti ed eventualmente di annullare delle modifiche specifiche.
Git è esattamente tutto questo. Ma, soprattutto, è stato creato da Linus Torvalds. Sì, proprio lui, quello di Linux. FUCK YOU NVIDIA!
Una delle peculiarità di git è che può significare di tutto, Anche Idiota!
Mentre nel 1991 nasceva Linux, si faceva largo durante i suoi sviluppi la necessità di un sistema di controllo delle versioni open source, facile da usare e robusto.
Prima del 2005 Linus utilizzava BitKeeper, ma essendo proprietario e di licenza chiusa questo binomio creava non pochi problemi a livello legale. Nel 2005, a seguito di queste necessità arriva il secondo più grande progetto di Linus che diventerà in seguito uno dei software più usati da tutti i programmatori e non del mondo: GIT
Gli obiettivi di Linus erano tre:
Se qualcuno ha mai aperto le pagine di manuale di git forse avrà notato che la descrizione del software è (cito letteralmente):
the stupid content tracker
Perché stupido? È presto detto.
Git significa infatti “idiota” o “stupido” in alcuni slang britannici.
Linus, che si definisce essere un “egoistico bastardo” a tal punto da volere che i suoi progetti si chiamino come lui, decide quindi di “darsi dello stupido” chiamando il progetto git.
Ma questo in realtà è solo l’inizio, infatti questo nome nasconde diversi significati. Sullo stesso file README di github si può leggere:
Il nome "git" è stato dato da Linus Torvalds quando ha scritto la prima versione. Lo descrisse come "lo stupido tracciatore di contenuti", ed il significato del suo nome varia in base al tuo umore:
- è una combinazione facilmente pronunciabile di tre caratteri, non ancora utilizzato da nessun comando UNIX. Il fatto che sia una storpiatura di "get" può essere rilevante o meno.
- stupido, spregevole, insopportabile. Scegline una dal dizionario dello slang.
- semplice
- acronimo di Global Information Tracker (Gestore di informazioni globale) se sei di buon umore e se attualmente pensi che funziona, se gli angeli cantano e la tua camera si riempie di luce!
- Goddamn Idiot Truckload of shit (Fottuto ammasso di stronzate) quando si rompe
In poche parole, git non ha un significato, ma in base alla situazione potete dargliene uno voi.
GIT è facilmente installabile ovunque.
Per quanto riguarda le distribuzioni Linux è un pacchetto presente nei repository di base di ogni package manager.
Per installare su Ubuntu e derivate scrivere su terminale:
apt install git
Per installare su Fedora scrivere su terminale:
dnf install git
Per installare su ArchLinux scrivere su terminale:
pacman -S git
Per altri sistemi operativi, sono disponibili i binari o gli installer sul sito ufficiale.
Git
è abbastanza banale da usare, ma è prima necessario comprendere la struttura su cui è basato.
Innanzitutto parliamo di un sistema di controllo delle versioni distribuito; la maggior parte dei sistemi di questo tipo non memorizza i file in sé, ma ne ricostruisce la struttura, partendo dalla storia, attraverso una piccola serie di file binari che ne tracciano le modifiche.
Git prevede 3 stati di memorizzazione per i file:
git
vengono aggiunti gli object relativi alle informazioni su quali sono i file modificati;Da qui in poi, in genere, il codice viene inviato nei repository remoti da noi impostati.
Giusto per essere chiari, possiamo identificare queste 3 aree anche all’interno del nostro file system:
.git
.Il primo movimento dalla working area alla staging area è detto “operazione di add”, mentre il secondo movimento da staging a repository è detto “operazione di commit”.
Si veda, qua in basso, la differenza tra tre repository prima della add, dopo la add e dopo il commit:
Quando si punta ad un *repository remoto*, gli scambi di codici con quello locale son detti:
“Remoto” in realtà è una parola un po’ fuorviante. GIT è in grado di connettersi ad un altro repository tramite un URL e scambiarsi i file facendo una fusione intelligente delle due storie dei progetti.
Tuttavia l’URL che si va ad inserire può essere tanto un indirizzo remoto quanto un’altra cartella del nostro file system.
Il senso di un’operazione del genere non è banale né solo didattica: ad esempio possiamo puntare una cartella del nostro file system che è poi sincronizzata con una cloud dati. Io utilizzo questo sistema per sincronizzare i miei progetti con Dropbox e Mega, ad esempio.
I “repository” puntati hanno poi dei “nomi” (in genere origin). Tramite questa capacità di poter associare un URL ad un nome, si dà la possibilità all’utilizzatore di poter gestire anche più di un repository alla volta, decidendo in base al caso dove effettuare pull e push. Si tratta di una tecnica utile quando si ha a che fare con progetti di lavoro dove non si hanno i permessi di creare branch nuovi o nel caso in cui si gestisce un fork di un progetto.
Iniziamo, quindi, dalle basi, creiamo un repository git nella nostra cartella di progetto: con il terminale creiamo una cartella e ci spostiamo in essa:
mkdir nomeprogetto
cd $_
NOTA:
Se la cartella esiste, non è necessario crearla, non interessa il suo contenuto, purché non sia già un repository git. Nel caso esistesse già, saltare il
mkdir
e fare direttamentecd
seguito dal percorso della cartella
Una volta dentro la cartella scrivere:
git init
A questo punto verrà creato un repository git vuoto.
Recentemente, per questioni legate al politically correct, il nome del branch iniziale dei progetti è stato cambiato da master
a main
. Tuttavia alcuni client di terminali per opzione predefinita ancora utilizzano la vecchia nomenclatura.
Per creare un repository git nel quale il nome del branch è main si può scrivere:
git init --initial-branch=main
ovviamente si può sostituire “main” con qualunque altro nome
Esistono due tipologie di repository, completi e minimali.
Normalmente sul proprio laptop si creano dei repository “completi”, ovvero che contengono tanto il codice quanto la parte controllata da GIT.
Ci si metta ora nell’ottica di dover creare un repository “remoto”, ovvero verso cui fare la push e la pull, in questo caso non si ha la necessità di avere anche il codice, ma solo i file necessari a git per ricostruire la storia.
Detta con una terminologia più tecnica, un repository “minimale” o “bare repository” è tale se non ha né working area né staging area.
Per creare un repository minimale il comando è:
git init --bare
Supponendo di voler mettere a confronto il contenuto di un repository normale e di uno minimale nel momento in cui contengono le stesse informazioni di progetto, la situazione sarebbe la seguente:
A sinistra si può vedere il vero file del progetto, in un repository normale.
Mentre a destra il contenuto di un repository bare, ovvero una serie di cartelle e file gestiti da GIT per il versionamento, ma non il file di per sé.
Come già detto in precedenza, un repository è minimale se manca di working area e stage area, ma questo ha un’altra conseguenza logica: Ogni repository ha, al suo interno, un repository minimale.
Se si entra nella cartella (nascosta) .git
del proprio progetto infatti, si può notare la stessa identica struttura di un repository minimale.
Ma l’operazione che più di frequente introduce un novizio a git, a la famosa git clone
, ovvero quell’operazione che, dato un repository remoto, ne scarica codice e repository in locale.
Per clonare un repository è necessario avere un url, quindi scrivere:
git clone URL
Si può anche specificare un nome di cartella diverso da quello del progetto:
git clone URL NuovoNomeCartella
In quest’ultimo caso, verrà creata una cartella con il nome indicato e quindi scaricato il reopsitory al suo interno.
Se si ha invece un repository locale, non clonato da remoto, si può pensare di aggiungere un indirizzo remoto in un secondo momento.
Spostarsi con il terminale in una cartella git, per agganciarsi ad un dato URL scrivere:
git remote add NOMEREPOSITORY URL
Quel “NOMEREPOSITORY” comunemente è origin
.
Si possono gestire più “repository remoti” alla volta:
git remote add NOMEREPOSITORY URL1
git remote add NOMEREPOSITORY2 URL2
Si noti che i nomi scelti per i repository non sono per niente vincolanti e scelti in totale libertà. Bisognerà, comunque, sempre tenerli a mente perché indispensabili quando si inizierà a dialogare tra locale e remoto.
]]>Si utilizza via riga di comando e consente di operare su file multimediali dai più svariati formati, dai più sconosciuti ai più recenti.
Tra le sue potenzialità: si può ritagliare un video, estrarne uno spezzone, unire più segmenti, cambiarne il formato, comprimerlo per guadagnare spazio su disco, ma anche aggiungere o estrarre tracce audio e sottotitoli, giusto per citare alcune delle operazioni più comuni.
Di seguito le informazioni su come installare FFmpeg su vari sistemi operativi.
Per maggiori informazioni, è sempre possibile consultare la pagina ufficiale dei download, che comprende anche eseguibili statici nonché versioni meno recenti.
Sebbene compilare da sé un software non sia la scelta più conveniente, FFmpeg costituisce un’eccezione: FFmpeg supporta un numero consistente di codec e formati (di cui sarà discusso più in avanti), ma alcuni vengono esclusi dai pacchetti pre-compilati per le motivazioni più disparate: problemi di licenza, di spazio occupato.
Un ulteriore vantaggio risiede nel fatto che compilare un software da sé potrebbe consentire al compilatore di ottimizzare un po’meglio l’eseguibile, qualora vengano forniti i giusti parametri.
Siccome la manipolazione di file multimediali può richiedere tempi e costi esorbitanti, e viste anche le continue migliorie (si pensi all’aumento delle prestazioni o alla risoluzione di bug), allora la compilazione nel caso di software critici come FFmpeg è ancor più indicata.
Per compilare FFmpeg senza alcuna modifica di sorta ai sorgenti:
git clone https://git.ffmpeg.org/ffmpeg.git
cd ffmpeg
./configure
make
make install
In caso di problemi, potrebbe essere necessario disabilitare alcune funzionalità o, in alternativa, installare i pacchetti di dipendenze mancanti.
A tal proposito, sulla wiki di FFmpeg è possibile trovare sia la guida ufficiale generica che le guide specifiche per le distribuzioni basate su Ubuntu o appartenenti alla famiglia di Red Hat.
FFmpeg è disponibile all’installazione via apt
su Ubuntu e derivate:
apt install ffmpeg
L’installazione su Fedora richiede un passaggio in più, siccome di base ffmpeg
non è disponibile nei repository ufficiali per loro scelta.
Dunque, bisogna prima abilitare i repository RPM Fusion (nello specifico, la repository “free”):
dnf install https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm
A questo punto, non resta che aggiornare l’elenco dei repository e installare ffmpeg
.
dnf update
dnf install ffmpeg
Nota: nel caso di Fedora Silverblue, le istruzioni sono identiche una volta sostituito il comando dnf
con rpm-ostree
(in più, è necessario riavviare).
Esistono tre diverse opzioni nel caso di Arch Linux: ffmpeg
(dalle repository ufficiali), ffmpeg-git
(da AUR, sincronizzato con la repository Git di FFmpeg) e ffmpeg-full
(anche qui da AUR, che include anche encoder e decoder solitamente lasciati fuori da altri pacchetti).
Solitamente, installare il pacchetto ffmpeg
è sufficiente:
pacman -S ffmpeg
Il pacchetto base per Windows è disponibile via Chocolatey:
choco install ffmpeg
In alternativa, via Winget:
winget install "FFmpeg (Essentials Build)"
Su Scoop è disponibile il pacchetto “full”:
scoop install ffmpeg
Su MacOS, FFmpeg è disponibile via Homebrew:
brew install ffmpegff
Grazie a Termux, è possibile utilizzare FFmpeg direttamente dal proprio smartphone Android.
Pur non essendo indicato per compiti più complessi (a causa delle prestazioni dei dispositivi mobili), resta comunque un’ottima opzione per manipolare video e audio in assenza di un computer.
pkg install ffmpeg
Per poter avere una vaga idea di come utilizzare al meglio FFmpeg (anche solo per comprendere che cosa cercare o come chiedere aiuto) è fondamentale conoscere, almeno a grandi linee, un po’di terminologia.
Un contenitore è una struttura di dati il cui nome, solitamente, coincide con l’estensione del file multimediale.
In un file multimediale, il suo contenitore si occupa di contenere i vari formati e metadati (autore, descrizione, tag, durata, data di creazione, e così via, alcuni dei quali sono inclusi anche negli stessi formati).
MP4, MOV, MKV, WEBM sono contenitori di flussi audio, video e sottotitoli.
Esistono anche contenitori specifici, sebbene meno utilizzati: M4V è il contenitore di un formato solo video (spesso H264) mentre M4A, analogamente, è il contenitore di un formato solo audio (spesso AAC).
Un formato è un flusso (stream) che rappresenta ciascuna delle singole parti che compongono il contenitore di un file multimediale.
Sono tre i tipi di formati principali da ricordare: audio, video e sottotitoli.
H264 (o AVC) è il formato video più diffuso in assoluto al momento di scrittura dell’articolo.
Analogamente, AAC è il formato audio che solitamente accompagna il formato video H264 nei contenitori MP4. L’intera lista dei formati per la propria installazione di ffmpeg è disponibile digitando
ffmpeg -formats
Quando un formato consente di conservare le informazioni senza perdita, a prescindere o meno che ci sia una compressione, allora si definisce lossless.
Al contrario, usare un formato lossy implica perdere qualità ad ogni successiva modifica del file.
I formati lossy comprimono meglio, occupano meno e richiedono meno risorse per essere inviati e riprodotti: sono i più adatti alla distribuzione.
I formati lossless, invece, sono preferibili in caso di archiviazione.
FLAC e WAV sono esempi di formati audio lossless.
MP3, AAC, OPUS e Vorbis sono esempi di formati audio lossy.
Molti altri formati sono lossy o lossless a seconda dei casi.
Un codec è spesso ed erroneamente confuso con quello che in realtà è un formato.
Derivando dall’unione di encoder e decoder, un codec fornisce entrambe le funzionalità per codificare o decodificare un flusso in un dato formato.
Esistono due tipi di codec: software e hardware. Solitamente i codec hardware, inclusi direttamente nei SoC, sono più rapidi ed efficienti delle controparti software.
Esempi di codec sono libx264, libmp3lame, libopus, libvpx, libdav1d L’intera lista dei codec per la propria installazione di ffmpeg è disponibile digitando
ffmpeg -codecs
In breve, muxer e demuxer lavorano sul contenitore, combinando o estraendo i singoli flussi.
Al contrario, encoder e decoder lavorano sui singoli flussi, convertendo ad un dato formato o effettuando l’operazione inversa.
Con transcoding, quindi con un’operazione di transcodifica, si intende l’utilizzo di un codec per convertire un formato in un altro formato (non necessariamente diversi).
Ciò implica che i dati di un file multimediale passano, in ordine, attraverso un demuxer, un decoder, un encoder e un muxer.
Non bisognerebbe MAI effettuare una transcodifica da un formato Lossy a un formato Lossless.
Di seguito alcuni esempi di utilizzo, tenendo a mente che la sintassi di ffmpeg
è la seguente:
ffmpeg [parametri globali] {[parametri di input] -i input} ... {[parametri di output] output} ...
Le parentesi quadre indicano che quegli argomenti sono facoltativi, le parentesi graffe indicano che sono mandatori, mentre i tre puntini di ellissi indicano che il precedente argomento può essere ripetuto una o più volte.
Per convertire un video intero da WEBM a MP4 non è necessario specificare alcun parametro aggiuntivo, oltre ai file di input e output:
ffmpeg -i video.webm video.mp4
Utilizzando -vn
si esclude il flusso video, preservando perciò solamente quello audio.
ffmpeg -i video.mp4 -vn video.aac
Tuttavia, questa soluzione non è la migliore: viene infatti effettuato il transcoding (o re-encoding), ossia, FFmpeg ri-codificherà da capo l’intera traccia audio: un gran spreco di risorse, tempo e di qualità.
La migliore soluzione, quando possibile, sta invece nel copiare il flusso così com’è in output specificando -c copy
: in altre parole, saranno effettuate le sole operazioni di demux e mux, quindi nessun decoding o encoding.
Ciò consente di ottenere risultati quasi istantaneamente, essendo il grosso del lavoro limitato dalla velocità del disco e non più dalla CPU:
ffmpeg -i video.mp4 -vn -c:a copy video.aac
Il :a
in -c:a copy
indica che il parametro è relativo, nello specifico, al flusso audio.
Per estrarre una parte di video è necessario ricorrere ai parametri -ss
, -to
e -t
, come nel seguente esempio:
ffmpeg -i video.mp4 -ss 00:00:04 -to 00:00:09.5 -c copy video_di_5_secondi_e_mezzo.mp4
Un comando del tutto equivalente, specificando durata (-t
) anziché la fine (-to
), è il seguente:
ffmpeg -i video.mp4 -ss 4 -t 5.5 -c copy 5_secondi_e_mezzo.mp4
Come visibile, la durata può essere espressa in vari modi, tra cui in formato HH:MM:SS (specificando eventualmente anche i millisecondi) o in formato unitario (in numero di secondi).
Per aumentare il volume di una traccia audio, è possibile ricorrere a un filtro lineare.
I filtri consentono di manipolare un flusso nei modi più disparati.
Il parametro -filter
(abbreviato -f
) viene fatto seguire dal nome del filtro e i parametri del filtro.
Nel seguente esempio, ad un file audio viene raddoppiato il volume predefinito (nota: sono supportate anche le unità in decibel, dB).
ffmpeg -i audio.ogg -filter:a volume=2 audio_v2.ogg
Parametro | Descrizione |
---|---|
-i |
Considera un URL di input (come un file o un collegamento) |
-ss |
Indica il punto in cui la riproduzione deve iniziare e può essere usato sia come parametro di input che di output (con qualche piccola ma importante differenza) |
-to |
Indica il punto in cui la riproduzione deve terminare; è un’alternativa a -t |
-t |
Indica la durata della riproduzione e dunque si configura come alternativa a -to |
-c |
Indica il codec da utilizzare (il valore copy indica nessun transcoding) |
-c:a |
Come -c , ma si applica soltanto ai flussi audio (alias di -acodec ) |
-c:v |
Come -c , ma si applica soltanto ai flussi video (alias di -vcodec ) |
-c:s |
Come -c , ma si applica soltanto ai flussi di sottotitoli (alias di -scodec ) |
-an |
Esclude tutti i flussi di tipo audio |
-vn |
Esclude tutti i flussi di tipo video |
-sn |
Esclude tutti i flussi di sottotitoli |
-f |
Filtro lineare (abbreviazione di -filter ) |
-f:a |
Come -f, ma si applica soltanto ai flussi audio (alias di -afilter ) |
-f:v |
Come -f, ma si applica soltanto ai flussi video (alias di -vfilter ) |
Sebbene effettuare una stream copy (-c copy
) sia vantaggioso, esiste anche un costo non indifferente che si manifesta in condizioni più particolari.
Ad esempio, se si volesse tagliare un file MP4 con una precisione al frame (usando -ss
e -to
/ -t
), allora il transcoding diventa necessario (ovvero, bisogna rinunciare a -c copy
).
Il transcoding infatti, sebbene comporti un costo computazionale maggiore, consente una precisione frame-per-frame.
Una stream copy, al contrario, è un’operazione imprecisa nel caso di un taglio siccome permette di avvicinarsi solo ai fotogrammi chiave più vicini (keyframes, frame che hanno un’importanza maggiore), sacrificando perciò la precisione per una maggiore efficienza.
I parametri -ss
, -t
e -to
possono essere indicati sia come parametri di input che come parametri di output.
La differenza fondamentale sta nel modo in cui FFmpeg li interpreta in fase di demux/mux e codifica/decodifica.
Quando posizionati come parametri di input, FFmpeg cercherà di avvicinnarsi il più possibile al punto voluto senza la sicurezza di alcuna precisione (per le stesse motivazioni descritte nel paragrafo precedente).
Come parametri di output, invece, il transcoding fa sì che il risultato sia quello cercato, al costo di ri-codificare tutti i frame.
È un errore convertire un file lossy in uno lossless: proprio per definizione, un’informazione lossy non possiede più lo stesso grado di dettaglio della sua analoga lossless.
Convertire un MP3 (lossy) in FLAC (lossless), ad esempio, costituisce un errore: non è possibile recuperare lo il livello di accuratezza perso, e l’unico risultato che si ottiene è nient’altro che un sensibile aumento dello spazio occupato.
L’ideale è limitare le conversioni da lossless a lossy o, se proprio necessario e in mancanza di alternative, da lossy a lossy.
Le conversioni da lossless a lossless invece non sono problematiche, generalmente.
FFmpeg in realtà non è un singolo eseguibile, ma il nome di un progetto che comprende un’intera suite di altri strumenti e librerie.
Mentre ffmpeg si occupa della manipolazione di file multimediali, ffplay ne consente la riproduzione (si pensi a una sorta di mpv) e ffprobe ne fornisce informazioni dettagliate (sul contenitore e sui flussi, come durata, bitrate, framerate, e così via).
Proprio come ffmpeg
, entrambi sono accessibili via riga di comando: ffplay
e ffprobe
, a cui si fa seguire il percorso di un file multimediale.
Dietro le quinte, tutti e tre gli strumenti a riga di comando qui citati fanno utilizzo delle medesime librerie, che costituiscono il cuore del progetto FFmpeg: le principali sono libavcodec (dedicata a encoder e decoder) e libavformat (dedicata a muxer e demuxer).
Per comprendere l’importanza di tali librerie, si consideri che sono molti gli editor e i player in GUI ad utilizzarle: VLC, mpv, Kdenlive, ImageMagick e, parzialmente, addirittura in browser come Chrome e Firefox.
La documentazione ufficiale è insostituibile per destreggiarsi con ffmpeg
, per conoscere tutti i parametri e il loro funzionamento (considerato anche che, tra i vari encoder/decoder, potrebbero avere comportamenti diversi o, peggio, non essere proprio supportati).
Molto utile è anche la wiki ufficiale su cui sono disponibili pagine guida per operazioni molto specifiche, come l’encoding di H.264 (il principale formato video in circolazione, attualmente) o la registrazione del desktop.
]]>Con il termine “getty” ci si riferisce ad una famiglia di software che instanziano un emulatore di terminale a schermo intero che generalmente fa da punto di login per un sistema UNIX. Probabilmente ogni utente linux che non sia esattamente novizio ha avuto a che fare almeno una volta direttamente con uno di questi software (spesso abbreviati in TTY).
Normalmente si può attivare una di queste console con la combinazione CTRL+ALT+FXX
(dove FXX è uno dei tasti funzione da F1
a F12
), in genere inoltre ogni sistema possiede 6 o 7 TTY utilizzabili (quindi da F1
a F6
o F7
).
I servizi getty generalmente son punti di partenza per i Display Manager quanto per i server grafici. In alcuni casi:
Tuttavia questi non sono numeri standard né vere e proprie convenzioni, quindi potrebbero variare da sistema a sistema.
Tramite DM e DE si viene automaticamente autenticati in un tty piuttosto che un altro. Ma tramite la combinazione di tasti: CTRL+ALT+FXX
come già detto si può cambiare tty.
Tuttavia, mentre si è già in un terminale virtuale senza GUI, su alcuni sistemi la shortcut si accorcia in ALT+FX
o addirittura ALT+freccie direzionali
.
Questo disabilita alcune combinazioni di tasti che normalmente si possono usare su linea di comando.
Come già detto, per getty si intende una famiglia di software con le caratteristiche sopra citate in comune. Questo ovviamente significa che ci son più software diversi utilizzati tra le varie distro. Le più comuni alternative di getty sono:
Tuttavia, normalmente, viene installato agetty
nei vari sistemi operativi, l’articolo quindi si concentrerà su quest’ultima.
Se pur è in genere il servizio di init che si occupa di avviare agetty, potrebbe essere bene sapere qualcosa sui parametri di avvio.
Innazitutto agetty legge i parametri sia dall’istruzione di avvio che dal file /etc/login.defs
(nel quale si trovano le opzioni già commentate).
Non si andranno ad elencare tutte le opzioni, eventualmente è comunque possibile trovare una lista completa tramite comando man
:
man agetty
Dunque:
--noclear
consente di evitare che venga cancellata la console al login ogni volta che si deve inserire il nome utente.--autologin
seguito da un username, permette di effettuare la login automaticamente senza chiedere né password né username (non usare se si ha ecryptfs
sulla home).In generale per ogni console virtuale presente nel sistema esiste un getty separato.
Attenzione: I file di configurazione di getty regolano l’accesso al sistema, potreste non essere in grado di fare più il login o di non farlo tramite tty sbagliando qualche configurazione. Consiglio innanzitutto di fare tutti i test su una console virtuale non tra quelle avviate con il sistema, inoltre se possibile fate un backup oppure fate i test su una macchina non importante per la vostra produttività.
Per cambiare il numero di console si deve modificare nel file di configurazione /etc/systemd/logind.conf
il parametro NAutoVTs
, il numero di default è 6.
I servizi SystemD legati a getty hanno nomi simili tra di loro e differiscono in genere per un numero:
getty@ttyX.service
Al posto di X
vi si può porre il numero del tty da eseguire. Il primo ad esempio potrà essere richiamato così:
getty@tty1.service
Si può creare al volo un altro tty con systemd, ad esempio per creare il settimo:
systemctl start getty@tty7.service
Attenzione:
Non sovrascrivete terminali esistenti, ad esempio ricreando il secondo (getty@tty2.service) potreste perdere la sessione utente corrente.
Come già specificato in precedenze, il file login.conf
si occupa già di prelevare un certo numero di tty.
Se tuttavia si dovessero creare situazioni in cui non si ha più accesso alle console, si potrebbe provare con disabilitare/abilitare manualmente delle sessioni tty alla login.
Innanzitutto per verificare quali servizi vengono automaticamente creati alla login da systemd senza passare per il file di login si può digitare:
ls /etc/systemd/system/getty.target.wants
A questo punto si possono disabilitare tutti:
systemctl disable getty@ttyN.service
Sostituendo il N
con i numeri corretti.
Non dovrebbe essere necessario abilitare alcun altro servizio, ma nel caso ci fossero problemi con la fase di login si può provare ad abilitarne uno così:
systemctl enable getty@ttyN.service
Per modificare i parametri di avvio si può creare un servizio systemd per un particolare getty:
Creare una cartella nel sistema con il nome del getty da modificare:
mkdir /etc/systemd/system/getty@ttyNUMERO.service.d/
Creare un file autologin.conf
, con la modifica della stringa di esecuzione aggiungendo i parametri desiderati (nell’ultima riga):
[Service]
ExecStart=
ExecStart=-/sbin/agetty -o '-p -- \\u' --noclear - $TERM
Sulla wiki di arch si hanno diversi esempi tra i più ricercati in genere.
Consiglio di provare le modifiche su tty a numerazione alta (TTY7 ad esempio) non gestiti dalla login.conf, e di provarli subito dopo scrivendo:
systemctl stop getty@ttyNUMERO.service
systemctl daemon-reload
systemctl start getty@ttyNUMERO.service
Per gestire le configurazioni di font e tastiera per il TTY si può scrivere sul file /etc/vconsole.conf
.
Si può abilitare il supporto ad una tastiera specifica tramite la keyword KEYMAP
, ad esempio per quella italiana:
KEYMAP=it
Si può abilitare il supporto per un tipo di font specifico, la lista dei font supportati è nella cartella /usr/share/kbd/consolefonts/
:
ls /usr/share/kbd/consolefonts/
Una volta selezionato un tipo in particolare si può scrivere nel file di configurazione assegnato a FONT
, ad esempio per un font adatto eventualmente a schermi con alte risoluzioni potrebbe essere utile utilizzare il font solar24x32
:
FONT=solar24x32
Per chi non fosse sicuro di cosa sta andando a leggere, Hadoop è un framework open source progettato da Apache per gestire grandi quantità di dati in modo distribuito su cluster di computer. È scritto per lo più in linguaggio Java e si può trovare il codice sorgente su Github. Insieme ad Hadoop viene installato il driver HDFS, ovvero il driver per Hadoop File System, il sistema di archiviazione distribuito di Hadoop.
Si presuppone che, il lettore, abbia gia Scala e Apache Spark (o Python e Pyspark). Inoltre deve avere Java installato e la variabile JAVA_HOME impostata con il path dell’installazione di Java.
I vari package manager non danno la possibilità di installare in maniera automatizzata, per gli utenti di ArchLinux si può trovare in teoria il pacchetto su AUR, pronto per essere installato tramite:
git clone https://aur.archlinux.org/packages/hadoop
cd hadoop
makepkg -si
Tuttavia anche questo spesso è mal funzionante e non esente da errori di compilazione. Ecco quindi un metodo funzionante e generico per l’installazione di Hadoop, indipendente dalla distribuzione o dal package manager.
Fondamentalmente si deve installare il software manualmente scaricando l’archivio, come già descritto in un articolo precedente.
Si acceda al sito web di hadoop per il download, quindi si scarichi la versione che si desidera dalla colonna “Binary download”. Nella schermata successiva scaricare il tar.gz tramite link in alto.
Alternativamente si può effettuare quest’operazione di download direttamente da terminale con il tool wget
, supponendo di voler scaricare la versione 3.3.6
:
wget https://dlcdn.apache.org/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz
In caso di versioni diverse, basta cambiare il numero di versione nel link.
Una volta effettuato il download basta decomprimere il file tar.gz
scaricato con l’apposito comando:
tar -xvzf hadoop*tar.gz
Quindi copiare la cartella sotto un punto del sistema raggiungibile a tutti gli utenti.
In genere i software di terze parti si installano sotto la cartella /opt
:
rm hadoop*tar.gz # in questo modo viene eliminato l'archivio
cp -r hadoop* /opt/hadoop
È quindi arrivato il momento di aggiornare le variabili d’ambiente. Per aggiornarle è necessario modificare uno dei file di avvio della nostra shell.
Ad esempio se si utilizza bash, si può pensare di modificare il file $HOME/.bashrc:
export HADOOP_HOME=/opt/hadoop
export PATH="$PATH:$HADOOP_HOME/bin"
export HADOOP_OPTS="-Djava.library.path=$HADOOP_HOME/lib/native"
export LD_LIBRARY_PATH=$HADOOP_HOME/lib/native
Oppure, al posto degli ultimi export, è possibile copiare le librerie nella cartella apposita:
ln -sf $PWD/libhadoop.a /usr/lib/libhadoop.a
ln -sf $PWD/libhadooppipes.a /usr/lib/libhadooppipes.a
ln -sf $PWD/libhadooputils.a /usr/lib/libhadooputils.a
ln -sf $PWD/libhdfs.a /usr/lib/libhdfs.a
ln -sf $PWD/libhdfs.so.0.0.0 /usr/lib/libhdfs.so
ln -sf $PWD/libhdfspp.a /usr/lib/libhdfspp.a
ln -sf $PWD/libhdfspp.so.0.1.0 /usr/lib/libhdfspp.so
ln -sf $PWD/libnativetask.a /usr/lib/libnativetask.a
ln -sf $PWD/libnativetask.so.1.0.0 /usr/lib/libnativetask.so
Ma è una pratica che non consiglio.
Per testare che tutto funzioni correttamente, aprire il terminale e quindi:
spark-shell
Se appare:
WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Allora qualcosa è andato storto, riprovare i vari step. Inoltre digitare:
hadoop version
Per verificare che la versione corrisponda.
]]>MPlayer è uno dei più famosi progetti open source nato per l’esecuzione di video (dallo stesso nome “Movie Player”), ha una discreta compatibilità di base che comunque può essere facilmente estesa con codecs esterni. Permette di riprodurre sia flussi audio che video.
Si può trovare la pagina del progetto su Github.
È installabile facilmente su tutte le distribuzioni, in genere infatti si può trovare nei repository base di tutti i vari package manager.
Per installarlo su Ubuntu e derivate digitare dal terminale:
apt install mplayer
Per installarlo su Fedora, bisogna attivare prima i repository RPMFusion:
dnf install http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm
Quindi digitare dal terminale:
dnf install mplayer mencoder
Per installarlo su ArchLinux digitare dal terminale:
pacman -S mplayer
Un utilizzo di base è semplicemente quello di avviarlo passando come parametro il nome del file da avviare:
mplayer percorso/filemultimediale
Quindi si può controllare il flusso tramite vari comandi:
Per riprodurre più file contemporaneamente (creando eventualmente delle playlist) è possibile semplicemente concatenarli separandoli da spazi a linea di comando:
mplayer percorso/filemultimediale1 percorso/filemultimediale2
È possibile ovviamente utilizzare i caratteri di espansione (Leggi l’articolo su come velocizzarsi nell’uso del terminale pt2) per selezionare più file contemporaneamente scrivendo poco. Ad esempio per avviare tutti i file mp3 in una determinata cartella:
mplayer *mp3
MPlayer è tanto “semplice” quanto potente, il suo utilizzo è scontato ed intuitivo se si vuole utilizzare in maniera scontata ed intuitiva, tuttavia possiede anche opzioni che permettono di sfruttarne altre funzionalità. Sono diverse le sue opzioni a riga di comando, eccone alcune:
In ogni caso è possibile sempre richiamare l’help con:
mplayer --help
Oppure in maniera più completa il manuale:
man mplayer
Che contiene tutte le opzioni.
Ecco qualche esempio di utilizzo:
Per far partire un file da 1 minuto e 30 secondi dall’inizio scriviamo:
mplayer -ss "00:01:30" percorso/file
Oppure:
mplayer -ss 90 percorso/file
Per far partire un video in 1080p scrivere:
mplayer -x 1920 -y 1080 percorso/video
Per riprodurre la radio “Radio freccia” usando massimo 16Mb la cache:
mplayer http://shoutcast.rtl.it:3060/ -cache 16384 -cache-min 10
Tuttavia, la portabilità a volte arriva con un costo non indifferente: la comodità di sviluppare in quel linguaggio, una più frequente complessità e la difficoltà a scrivere codice per compiere operazioni spesso molto banali in altri linguaggi di programmazione.
Per fornire qualche esempio si pensi all’aritmetica dei numeri decimali (nativamente non supportata), alla mancanza di supporto per strutture dati complesse e così via.
Questa situazione rende Bash idoneo per script molto semplici, ma non così tanto per software più complessi o che tendono velocemente a evolvere.
Esiste un’alternativa?
Nota bene:
Per una panoramica su come fare calcoli in bash leggi anche: #howto - Fare calcoli con Linux: Bash e non solo.
Potrebbe non essere immediatamente noto a chiunque, ma non è obbligatorio che gli script siano scritti nel linguaggio della Shell attualmente utilizzata.
La prima riga di uno script è utile proprio a questo: viene fatta iniziare con lo Shebang, la sequenza di caratteri #!
, seguita dal percorso assoluto del programma interprete (più eventuali parametri, se necessario). Nel caso di uno script in Bash:
#!/bin/bash
Specificare il percorso assoluto non è sempre semplice (determinati interpreti si potrebbero trovare in una delle tante svariate cartelle incluse nel $PATH
).
Oppure, in caso l’utente stia utilizzando un sistema non conforme a FHS, allora i percorsi potrebbero essere totalmente diversi.
Perciò, in caso di dubbi sul percorso, è buona norma ricorrere ad env
aggiungendolo prima del nome dell’eseguibile in questione:
#!/usr/bin/env bash
Nel caso si voglia utilizzare un qualsiasi altro linguaggio, ad esempio Python, è necessario sostituire “bash” con “python” (o ancora meglio “python3”, nel caso si scelga di utilizzare Python 3 su un sistema dove è installato anche Python 2)
#!/usr/bin/env python3
Anche se l’estensione del file raccomandata dovrebbe essere attinente al suo contenuto (ad esempio che per uno script in Python bisognerebbe scegliere il suffisso .py), è interessante notare che non è obbligatorio inserire l’estensione giusta: lo Shebang corretto è tutto ciò che serve per eseguire uno script, in quanto l’estensione è ininfluente.
Linguaggio | Shebang |
---|---|
Bash | #!/usr/bin/env bash |
JavaScript (NodeJS) | #!/usr/bin/env node |
JavaScript (Deno) | #!/usr/bin/env -S deno run |
Julia | #!/usr/bin/env julia |
Lua | #!/usr/bin/env lua |
Perl | #!/usr/bin/env perl |
PHP | #!/usr/bin/env php |
Powershell | #!/usr/bin/env pwsh |
Python2 | #!/usr/bin/env python2 |
Python3 | #!/usr/bin/env python3 |
Ruby | #!/usr/bin/env ruby |
Il parametro -S
di env
va usato ogni volta che i parametri seguenti il nome dell’eseguibile vengano divisi da spazi (e perciò non considerati come un tutt’uno).
Ovviamente, non va dimenticato di dare ad ogni script i giusti permessi:
chmod +x percorso_eseguibile
. In caso contrario, le shell si rifiuteranno di eseguire lo script.
Potrebbe non sembrare un gran guadagno: in questa semplice e specifica casistica, in effetti, lo stesso risultato si sarebbe potuto ottenere invocando il nome dell’eseguibile prima del file sorgente.
Nel caso dei linguaggi compilati, però, la situazione si complica perché il codice sorgente non coincide con il codice eseguibile.
Questo implica che ogni cambiamento “al volo” nel sorgente non si rispecchi nell’eseguibile fin tanto che il tutto non viene ricompilato manualmente.
Scriptisto consente di nascondere tutto il lavoro in più richiesto dai linguaggi compilati.
In più, l’overhead è minimo (circa 1 ms riportato sugli script eseguiti senza apportare cambiamenti), quindi l’uso extra di risorse è praticamente nullo.
Tra i vantaggi:
Tra i chiari svantaggi c’è sicuramente il fatto che potrebbero verificarsi problemi di completamento, formattazione, evidenziamento negli IDE.
Scriptisto specifica all’interno del file sorgente stesso le dipendenze richieste e il comando di compilazione. Questo vuol dire che questa sintassi extra (automaticamente ignorata da Scriptisto in fase di esecuzione, chiaramente) possa essere tuttavia vista come errore in fase di modifica da parte degli editor di testo più avanzati.
Sebbene parte del problema si possa aggirare facilmente solo utilizzando commenti specifici del linguaggio che si intende usare (più informazioni in seguito), resta il problema dello Shebang (che alcuni editor potrebbero automaticamente rilevare e ignorare, ma non sempre è scontato) e delle dipendenze (Scriptisto sa se i sorgenti dipendono da codice esterno, mentre gli editor e gli IDE no).
Si tratta di un eseguibile che richiede i soli bash
ed env
, supportato perciò su virtualmente ogni distribuzione.
Il download si trova sulla pagina dei rilasci, nello specifico si tratta del file .bz2
(uno per Linux, l’altro per MacOS).
L’eseguibile si trova all’interno dell’archivio per preservare il permesso di esecuzione, dunque per scompattarlo bisogna usare:
tar xjvf scriptisto*.bz2
Fatto ciò, è possibile eseguire Scriptisto con ./scriptisto
.
È consigliato spostare l’eseguibile in una delle cartelle del
$PATH
così che anche solo “scriptisto” funzioni, anziché dover specificare ogni volta il percorso relativo o assoluto dell’eseguibile.
Nel caso in cui sia installato Cargo (per Rust), l’installazione è comune a tutte le distribuzioni:
cargo install scriptisto
Il pacchetto di installazione .deb
per Debian e derivati si trova sulla pagina dei rilasci.
Una volta scaricato, il comando di installazione è il seguente (potrebbero essere necessari i permessi di root):
dpkg -i scriptisto*.deb
Analogamente, sulla pagina dei rilasci è disponibile il pacchetto .rpm
, così installabile:
rpm -i scriptisto*.rpm
Si può invece trovare scriptisto su AUR per quanto riguarda archlinux :
git clone https://aur.archlinux.org/scriptisto.git
cd scriptisto
makepkg -si
Per compilare da sorgente il software bisogna scaricare da GitHub i file e compilarli con Cargo:
git clone https://github.com/igor-petruk/scriptisto.git
cd scriptisto
cargo install --path .
Consultare la pagina per le installazioni.
Prima di creare un nuovo progetto con Scriptisto bisogna consultare i linguaggi supportati:
scriptisto template ls
In base al template scelto, Scriptisto si occuperà di creare una base quasi minimale da cui partire. Automaticamente, Scriptisto sceglie per la propria configurazione interna il prefisso più comodo, ossia quello che coincide con i commenti del dato linguaggio.
In altre parole, le righe scriptisto-start
e scriptisto-end
(che indicano inizio e fine della configurazione) avranno prefisso //
sui linguaggi C-like, così che gli editor di testo possano ignorare senza problemi la parte estranea al codice sorgente.
Nel caso del linguaggio di programmazione C
, ad esempio:
scriptisto new c | tee ./hello-world-in-C
Dopodiché va solo abilitato il file ad essere un eseguibile mediante chmod
:
chmod +x ./hello-world-in-C
Non rimane altro che eseguire lo script:
./hello-world-in-C
I sorgenti di Scriptisto sono disponibili su GitHub, inclusa la Wiki.
]]>