Annullare ultimo commit in Git

Se sei interessato ad imparare Git, abbiamo una guida che fa al caso tuo.

Oh no, presi dalla frenesia abbiamo modificato nuovamente quel file dopo il commit.

Per annullare l’ultimo commit eseguito e riportare i file fuori dallo stage come file modificati e unstaged, non esiste un comando ufficiale. Dobbiamo quindi effettuare un reset e rieseguire il commit. Vediamo come:

Dopo il nostro commit “sbagliato”, eseguiamo un git reset in in questo modo:

Questo comando dice a git di lasciare la nostra directory di lavoro com’era prima dell’ultimo commit e lo annulla. A questo punto riavrete i file come unstaged proprio come se fossimo tornati in dietro nel tempo. A questo punto eseguiamo le modifiche che desideriamo ed aggiungiamoli con git add:

A questo punto eseguiamo il commit delle modifiche riusando il vecchio messaggio di commit. Il comando git reset  ha, a tutti gli effetti, spostato il “vecchio” HEAD  in .git/ORIG_HEAD :

Se volessimo riscrivere il messaggio di commit e non utilizzare quello precedente, possiamo indicare il flag -c  (quindi minuscola): si aprirà un editor in cui scrivere il nuovo messaggio di commit.

Errore Git “Please commit your changes or stash them before you merge.”

Quando ci troviamo ad aggiornare la copia di lavoro locale con Git, usando il comando git fetch  o git pull , spesso ci troviamo di fronte all’errore [..] Please commit your changes or stash them before you merge.[..].

Git ci sta dicendo che il nostro lavoro locale è andato avanti rispetto a quello remoto e che ci potrebbero essere delle perdite. Come possiamo vedere, Git stesso ci consiglia di fare un commit o uno stash e riprovare ad eseguire il comando.

Se invece volessimo scartare le modifiche locali, e forzare la copia locale a sincronizzarsi a quella remote?  Possiamo usare una combinazione di comandi:

Attenzione: questo comando potrebbe farvi perdere le modifiche locali delle quali non avete fatto il commit!

Eseguendo questi comandi, prima scarichiamo dal server le ultime modifiche con git fetch , poi, portiamo il puntatore interno di Git allo stato precedente (cioè l’ultimo commit salvato) e poi effettuiamo una pulizia di tutti i file (e directory) non tracciati.

 

Gestire i rami (branch) in Bitbucket

Cosa sarebbe Git senza le ramificazioni? Esistono molti tool online per la gestione dei repository, e sicuramente BitBucket è uno dei più apprezzati. Quando lavoriamo sulla nostra macchina, però, dobbiamo sincronizzare i rami locali con i rami remoti per rendere tutto più efficace. Esistono due modi principali per creare dei branch in Git e poi sincronizzarli (eseguendo un push origin) con il server remoto di BitBucket. Vediamoli.

Creare un ramo in Bitbucket

  1. Andiamo nella pagina del nostro Repository, in alto clicchiamo su Create branch
  2. Dalla schermata successiva, selezionare il ramo di partenza (solitamente, master) e il nome del nuovo ramo, clicca su Create
  3. A questo punto il branch, in remoto, verrà creato. La nostra copia locale del progetto, però, non lo sa ancora. Sincronizziamola con un git fetch :
  4. Proviamo ora a cambiare un file di lavoro e ad eseguire un git push :
  5. Fatto.

Creare un ramo locale

La seconda opzione è quella di creare un branch in locale e successivamente eseguire un git push. Ovviamente il repository su cui state lavorando deve già essere associato ad un repository BitBucket.

  1. Per prima cosa, creiamo il ramo:
  2. Spostiamoci sul ramo appena creato:
  3. A questo punto, proviamo a cambiare qualche file ed effettuiamo un commit , seguito da un git push :
  4. Fatto.

Verifichiamo che il branch ci sia

Dalla pagina del nostro Repository su BitBucket, verifichiamo che il ramo appena creato sia presente tra i branch:

Ti interessa Git? Consulta la nostra guida a Git.

Spostare dei commit su un nuovo ramo in Git

Molto spesso ci troviamo davanti a questo tipo di problema: per errore o inesperienza, eseguiamo dei commit  mentre ci troviamo sul ramo sbagliato. Come facciamo a spostare gli ultimi commit su un nuovo ramo o su un ramo preesistente?

Ci troviamo in una situazione analoga a questa:

Dove gli ultimi due commit, cioè af65fcd  e e577582  sono quelli da spostare su un branch diverso. Vogliamo, cioè arrivare ad una situazione analoga a questa:

 

Muovere commit su un nuovo ramo

Nel caso volessimo spostare gli ultimi commit  su un nuovo branch , l’operazione è abbastanza semplice e non dovrebbe dare problemi.

Il comando centrale di questa procedura è

che dice sostanzialmente di spostarsi indietro di 2 commit: possiamo indicare il numero di commit che ci serve scavalcare. In alternativa, possiamo indicare l’hash del commit, se lo conosciamo, ad esempio:

Non perderemo alcun commit, semplicemente li abbiamo staccati e associati al ramo nuovoramo.

Muovere commit su un ramo esistente

Il metodo precedente è basato sul fatto che nuovoramo è appunto un ramo creato per l’occasione. Ma se volessimo spostare gli ultimi n commit su un ramo già esistente?

In questo caso dovete effettuare prima un git merge  tra il ramo e il master  prima di eseguire il git reset  come nell’esempio precedente. Se non lo fate perderete il vostro lavoro. Vediamo come eseguire questa procedura:

 

10 anni di Git: un’intervista al creatore Linus Torvalds

Più di 10 anni fa, la community di sviluppo del kernel Linux si trovò dinanzi un problema: il sistema di controllo delle versioni BitKeeper aveva interrotto la loro licenza e nessun altro sistema andava più bene per i loro bisogni. Linus Torvalds, il mitico creatore di Linux, prese la situazione in mano e sparì per un intero weekend per riemergere la settimana seguente con Git. Oggi Git è sicuramente il sistema più usato e richiesto nella gestione delle versioni.

Noi abbiamo dedicato un’intera e completa guida a Git e sul come gestire le versioni del software. Se siete qui per imparare, dategli uno sguardo!

Per celebrare questo traguardo, il sito Linux.com ha intervistato Linux Torvalds chiedendogli qualche storia behind-the-scenes e in generale cosa ne pensa dello stato attuale del progetto. Noi vi riportiamo qui questa intervista, tradotta integralmente.

Perché hai creato Git?

Non ho mai davvero pensato e voluto realizzare un sistema di gestione dei sorgenti, e penso che sia la cosa meno interessante in tutta l’informatica (con la possibile eccezione dei database). Ho odiato tutti i sistemi profondamente. Ma poi BitKeetper è arrivato e ha cambiato questa visione che avevo del controllo di versione. BitKeeper ha la maggior parte delle funzioni necessarie e in più offre il merge tra il repository locale e quello remoto ed è davvero una gran cosa. Il fatto che il controllo fosse distribuito ha fatto sparire di colpo i vecchi problemi che avevano gli altri sistemi e tutta la questione del “chi può cambiare cosa”. Mostrò che tutto questo poteva essere evitato semplicemente facendo lavorare ognuno su un repository locale. Certo, aveva i suoi problemi: c’erano alcune scelte tecniche che causavano problemi (rinominare i file era terribile), ma il principale lato negativo era il fatto che siccome non era open source, c’erano un sacco di persone che semplicemente si rifiutavano di usarlo. Così, mentre diversi sviluppatori usavano BitKeeper (perché è gratuito per i progetti open source), non era usato da altri. Ci ha molto aiutato nello sviluppo del kernel, ma resistevano piccoli punti da risolvere.

Si arrivò a un punto quando Tridge (Andrew Tridgell) cominciò a fare il reverse-engineering del (relativamente) semplice protocollo di BitKeeper, cosa che era contro le norme d’uso del software. Ho passato diverse settimane (ma a me sono sembrati mesi) provando a fare da mediatore tra Tridge e Larry McVoy (il capo di BK, ndr) ma alla fine la cosa non funzionò. Così ad un certo punto ho deciso di non poter continuare a utilizzare BK, ma neanche di voler tornare ai tempi bui pre-BK. Tristemente, al tempo, anche se c’erano altri sistemi che provavano ad implementare la logica del software distribuito, nessuno lo faceva davvero bene, soprattutto in remoto. Anche le performance che volevo nel trasferimento dati in remoto non erano soddisfacenti, e inoltre ero preoccupato dell’integrità del codice. Così ho semplicemente deciso di scrivere un sistema nuovo.

Qual è stato il tuo approccio? Sei stato sveglio tutto il weekend o l’hai scritto in orario di lavoro?

Heh. Puoi vedere da te come ha preso forma guardando la storia del repository di Git stesso. C’è voluto circa un giorno per arrivare ad essere “self-hosted” così da poter usare Git per sviluppare.. Git. Il primo giorno quindi, i commit erano, diciamo, nascosti, ma tutto era già lì. Ho lavorato maggiormente durante il giorno, ma se guardate ci sono due istantanee fatte verso la mezzanotte e un paio alle 2. La parte più interessante però è sul quanto velocemente ha preso forma; il primo vero commit nel repository non contiene molto codice, ma poteva già eseguire il commit di se stesso. Il vero trucco però è sul come organizza i dati.

Ho provato a stressare il sistema fin tanto che prendeva forma in circa 10 giorni (a quel punto ho provato a fare il mio primo commit del *kernel*), ma non sono finito nella pazzìa del programmare senza sosta. Infatti la prima versione è abbastanza piccola, non è composta da molto codice, perché tutto dipendeva dal fatto che l’idea base fosse buona. Ci avevo pensato su per un po’ prima che l’intero progetto iniziasse. Avevo visto i problemi che altri avevano. Avevo visto quello che volevo evitare.

Ha raggiunto le tue aspettative? Come sta funzionando oggi secondo te? Ci sono limitazioni?

Sono molto contento di Git. Funziona notevolmente bene per il kernel e sta ancora soddisfacendo tutte le mie aspettative. Quello che mi sembra interessante è il modo in cui è stato adottato da così tanti altri progetti. Sorprendentemente veloce. C’è molta resistenza nel cambiare il sistema di controllo della versione, basta guardare quanto tempo CVS e anche RCS sono rimasti in giro, ma ad un certo punto Git ha preso il sopravvento.

Quale pensi sia il motivo di questa grande diffusione?

Penso che molti altri si siano sentiti frustrati dagli stessi problemi che mi hanno fatto odiare SCM e, sebbene ci siano stati molti progetti che tentassero di risolvere uno o due piccoli casi che facevano impazzire la gente, non c’era veramente niente di simile a Git che davvero affrontasse di petto questi problemi. Anche se molti non capirono l’importanza della parte riguardante la logica “distribuita” (e molti la contrastavano), una volta che si resero conto che ciò consentiva backup semplici e affidabili e che tutti potevano avere i propri repository di test privati senza preoccuparsi di alcuna politica sui permessi del “chi fa cosa”,  adottarono Git senza voltarsi indietro.

Git durerà per sempre o prevedi un altro sistema fra altri 10 anni? Sarai ancora tu a scriverlo?

Non lo scriverò io, no. E forse vedremo qualcosa di nuovo in dieci anni, ma vi garantisco che assomiglierà sicuramente a Git. Non che Git sia perfetto, ma ha realmente aggiustato tutti i problemi basilari degli altri sistemi.

Nessuna falsa modestia 😉

Perché Git funziona così bene per lo sviluppo di Linux?

Beh, è ​​stato ovviamente progettato per il nostro flusso di lavoro, quindi è parte di esso. Ho già citato molte volte l’intera parte “distribuita”, ma vale ripeterla. È stato anche progettato per essere abbastanza efficiente per un progetto grandicello come Linux, ed è stato creato per fare cose che la gente considerava “difficili” prima di Git – perché queste sono le cose che anche *io* faccio ogni giorno.

Giusto come esempio: il concetto di “fusione” tra rami viene generalmente considerato qualcosa di complesso e difficile nella maggior parte degli SCM. Si dovevano pianificare i merge con calma, perché potevano essere distruttivi. Questo per me non è accettabile, dal momento che quotidianamente faccio decine di merge e il problema a cui devo dedicarmi è testare il risultato del mio codice, non perdere tempo sul merge stesso. La “parte Git” del mio lavoro dura giusto un paio di secondi, di solito ci vuole di più solo per scrivere la spiegazione del merge. Quindi Git è stato fondamentalmente progettato e scritto per i miei requisiti, e si vede.

Molte persone sostengono che Git è solo per persone super intelligenti. Anche Andrew Morton ha detto che Git è “espressamente progettato per farti sentire meno intelligente di quello che tu pensi di essere.” Qual è la tua risposta a questo?

Penso che sia stato vero in passato, ora non più. Ci sono diverse ragioni per le quali le persone si sono sentite così, una sola però è rimasta: “puoi fare le cose in tanti modi”.

Puoi fare molte cose con Git perché molte funzioni sono state create per lavorare insieme ad altre persone. Git comprende un set di strumenti molto potenti e spesso all’inizio ci si può sentire sopraffatti, però questo offre anche il vantaggio che la stessa operazione si può fare in modi diversi, e tutti “funzionano”. Generalmente il modo migliore di imparare Git è iniziare con comandi molto semplici e non guardare neanche le altre funzioni finché non si è abbastanza bravi con le basi.

Ci delle ragioni storiche per le quali Git è stato spesso considerato complicato. Una di queste è che è stato davvero complicato. Le persone che hanno iniziato a usare Git molto presto (per lavorare sul kernel), hanno dovuto apprendere davvero un insieme molto scomodo di script per far funzionare tutto. Questo perché tutto lo sforzo all’inizio fu indirizzato per far funzionare “la tecnologia di base” e poco per renderlo semplice. Così Git (meritatamente) si è fatto una brutta fama all’inizio, perché dovevi sapere esattamente cosa stavi facendo. Tutto questo è stato vero soltanto per i primi sei mesi, forse un anno.

L’altro grande motivo che ha fatto pensare che Git fosse difficile è che Git è molto diverso dagli altri sistemi. Ci sono molti sviluppatori che hanno usato CVS (o altri) per un decennio o due. Git non è CVS, neanche lontanamente. I comandi sono diversi. Non abbiamo neanche immaginato di farlo simile a CVS, anzi il contrario. E se hai usato un sistema CVS-like per molto tempo, è ovvio che Git possa apparirti complicato e stranamente diverso. Perché le mie versioni sono basate su un HEX da 40 caratteri e non su una stringa tipo “1.3.1.”?

Git però non è “inutilmente diverso”. Le differenze sono necessario. È solo che ha fatto alcune persone pensano che sia più complicato di quanto lo sia perché provengono da un background molto diverso. La fortuna è che là fuori molti programmatori non hanno neanche mai usato CVS, e il loro prima sistema è proprio Git.

Pensi che lo sviluppo del kernel Linux sarebbe potuto crescere così rapidamente senza Git? Perché sì o perché no?

Beh, “senza Git” di sicuro. Ma avrebbe richiesto che qualcun altro, prima o poi, avesse creato qualcosa di equivalente: un sistema di controllo delle versioni distribuite efficace proprio come Git. Avremmo sentito certamente il bisogno di qualcosa *come* Git.

Qual è la tua opinione su GitHub?

GitHub è un eccellente servizio di hosting. Non ho niente contro. Ora, le lamentele che ho avuto riguardo GiHub come piattaforma di sviluppo- ovvero fare commit, pull, tenere traccia dei bug, etc. – sono che non funziona molto bene per tutti. Non è nemmeno vicino, purtroppo, neanche per il kernel: è troppo limitato.

Questo è in parte a causa del modo in cui il kernel viene sviluppato, ed in parte è dovuto al fatto che certe interfacce di GitHub incoraggiano i cattivi comportamenti. I commit fatti su GitHub, per esempio, hanno messaggi scritti male, proprio perché l’interfaccia non blocca questa prassi. Fixando questi dettagli il tutto lavorerà sicuramente meglio, ma difficilmente sarà  appropriato per il kernel linux.

Qual è l’utilizzo più interessante che hai visto per Git e/o GitHub?

Sono contento che abbia reso così facile avviare un nuovo progetto. L’hosting è sempre stato un punto ostico, e con Git e GitHub è quasi banale creare un piccolo progetto dal nulla. Non importa quale sia il progetto: quello che conta è che tu lo puoi fare.

Hai progetti laterali, attualmente? Magari un software ancora più brillante che dominerà lo sviluppo del software per gli anni a venire?

Niente di programmato. Ma vi terrò aggiornati.