Cosa devo fare quando ho già aspettato troppo a lungo tra i commit?


100

Ero cattivo ... Troppo "codice da cowboy", non abbastanza impegno. Ora, eccomi qui con un impegno enorme. Sì, avrei dovuto impegnarmi da sempre, ma ormai è troppo tardi.

Cos'è meglio?

  1. Fai un commit molto grande che elenca tutte le cose che ho cambiato
  2. Prova a suddividerlo in commit più piccoli che probabilmente non verranno compilati, poiché i file hanno più correzioni, modifiche, nomi di metodi aggiuntivi, ecc.
  3. Prova a fare inversioni parziali dei file solo per i commit appropriati, quindi ripristina le nuove modifiche.

Nota: al momento sono l'unico programmatore che lavora a questo progetto; l'unica persona che guarderà uno di questi commenti di commit sono io, almeno fino a quando assumeremo più programmatori.

A proposito: sto usando SVN e Subclipse. Ho creato una nuova filiale prima di apportare una di queste modifiche.

Ulteriori informazioni : ho posto una domanda separata relativa a come sono arrivato a questa situazione in primo luogo: come prepararsi per riscrivere la colla di un'applicazione


2
Quale programma di controllo versione stai usando? Molti hanno moduli che ti permettono di suddividere le tue modifiche in "hunk", cioè gruppi di linee modificate, che ti permetterebbero di raggruppare le tue modifiche nel modo che preferisci e di distribuire le mod di un file su più changeset. Ad esempio, mercurial ha l'estensione "accantonamento". Ovviamente dovresti comunque verificare se ogni batch di modifiche viene compilato, se questo è importante per il tuo processo. Se valga la pena, il problema dipende da te e dal tuo negozio.
alexis,

6
Almeno controllalo sul ramo, in modo da non perdere le modifiche.
Rory Hunter,

2
Puoi continuare a farti la domanda e aspettare ancora di più, oppure effettivamente impegnarti e gestire qualsiasi pasticcio che crea ... E poi ... non farlo più!
haylem,

40
# 1, prega per il perdono, poi vai avanti e non peccare più :)
Peteris,

5
La domanda più importante che dovresti porti è: "come posso cambiare le mie cattive abitudini per evitare che ciò accada di nuovo". Non ci dovrebbe essere alcun motivo per impegnarsi non almeno una volta al giorno, meglio più spesso.
Doc Brown,

Risposte:


52

Per rispondere, devi chiederti come ti aspetti di utilizzare i risultati di questi commit in futuro. I motivi più comuni sono:

  • Per vedere quale versione è stato introdotto un bug.
  • Per capire perché è presente una determinata riga di codice.
  • Per unire in un altro ramo.
  • Per poter verificare una versione precedente per la risoluzione di un problema che un cliente o un tester sta riscontrando in quella versione.
  • Essere in grado di includere o escludere determinate parti da una versione.

I primi due motivi possono essere forniti altrettanto bene con un unico check-in, supponendo che sia possibile creare un messaggio di check-in che si applichi ugualmente bene a ciascuna riga del codice modificato. Se sei l'unico programmatore, i piccoli commit non renderanno la tua unione più semplice. Se non prevedi di rilasciare o testare solo una parte delle modifiche non inviate, gli ultimi due motivi non si applicano.

Ci sono altri motivi per fare piccoli commit, ma lo sono per mentre sei nel mezzo dei cambiamenti, e quel tempo è passato. Tali ragioni stanno rendendo più semplice il ripristino di un errore o un cambiamento sperimentale e facilitando la sincronizzazione con i colleghi senza enormi fusioni spaventose.

Dalla mia comprensione della tua situazione mentre la descrivi, sembra che ci sia poco o nessun beneficio a dividere il tuo impegno a questo punto.


Risposta eccellente! Anche se non mi sento meno dispiaciuto di non aver fatto i piccoli impegni, mi sento molto meglio su cosa dovrei fare per riprendere un buon comportamento nel modo più produttivo possibile.
durron597,

1
L'altra cosa su 3 e 5 è che ogni lavoro che fate ora, al fine di permettere loro di accadere, si potrebbe aspettare fino a quando è effettivamente necessario e poi fare lo stesso lavoro. Probabilmente sarà un po 'più difficile in futuro perché il tuo ricordo di ciò che hai fatto è sparito. Ma poi di nuovo, probabilmente non ne avrai mai bisogno.
Steve Jessop

Nella mia esperienza, è difficile e fragile fare affidamento sui commenti sul controllo della versione per raccontare una storia del motivo per cui il codice è presente (ovvero i motivi 1 e 2). Se stai usando SVN con una diramazione, la cronologia del commit andrà persa all'unione (comunque starai meglio con cose più moderne come git). Quindi quelli sono IMHO meglio serviti con commenti.
Hans-Peter Störr,

1
@hstoerr - se sei su Subversion 1.5 o versioni successive, puoi conservare la cronologia con l'opzione --reintegrate al momento dell'unione.
Dustin Kendall,

1
git add -p è il tuo migliore amico qui. Mi sono innamorato di quella caratteristica. In questo modo posso eseguire il commit delle mie modifiche standard di codifica in commit separati e mantenere isolate le relative modifiche al codice.
Spidey,

39

Penso che qualunque cosa tu faccia, cerca di evitare di archiviare il codice che sai che non verrà compilato.

Se ritieni che la tua terza opzione sia fattibile, potrebbe essere un buon modo per farlo, purché tu possa assicurarti che la sequenza di commit non crei un sistema incompatibile. Altrimenti, fai solo un grande impegno. È brutto, ma è semplice, veloce e lo fa. Andando avanti, impegnarsi più spesso .


L'opzione tre è possibile ma richiederebbe molto tempo. Penso che farò solo l'opzione 1
durron597,

3
Quali sono gli svantaggi del commit del codice che non verrà compilato o compilato in un ramo di funzionalità (o simile) che sono così terribili da costringere qualcuno a evitare di farlo "qualunque cosa faccia"? Immagino che gli impegni davvero terribili potrebbero essere evitati dagli altri, che è l'unica vera ragione per cui li eviterei in primo luogo (supponendo, ovviamente, che gli impegni non vengano rilasciati ).
Kenny Evitt,

3
Il "evitare di archiviare il codice che non verrà compilato" si applica solo a una base di codice / ramo condivisa. In un progetto one-man o in un ramo di sviluppo one-man, sostengo che è più importante solo apportare le modifiche in VC in modo da non perdere nulla.
Stephen C,

3
@StephenC ad esempio perché rompe strumenti come git-bisect. Se il codice viene compilato / eseguito continuamente e è necessario trovare una regressione se viene compilato continuamente, è possibile solo la ricerca binaria (senza contare che se esiste una regressione nella porzione di codice, si rimane con grandi cambiamenti da leggere anziché restringere giù).
Maciej Piechotka,

@MaciejPiechotka - Beh, ovviamente se hai bisogno di usare strumenti specifici sulle tue filiali private e richiedono che il codice sia compilabile, allora fallo. Ma questo non è tipico per un progetto / ramo di una persona.
Stephen C

19

Il motivo più importante per effettuare commit frequenti, piccoli e significativi è di aiutare a comprendere la storia del codice. In particolare, è molto difficile capire come è cambiato il codice se è difficile generare differenze comprensibili.

L'opzione 1 offusca la cronologia delle modifiche apportate, ma in caso contrario non causerà alcun problema.

L'opzione 2 offusca la cronologia delle modifiche apportate, possibilmente un po 'meno dell'opzione 1, ma potrebbe causare altri problemi a se stessi o agli altri se assumono o concludono in altro modo che i commit sono distinti, ad esempio possono essere uniti in altri rami in modo indipendente. A meno che non ci sia una forte ragione pratica per cui questo è preferito rispetto all'opzione 1, questo è meno ideale di esso.

L'opzione 3 è la migliore, a parità di altre condizioni, ma se, come descritto altrove, ciò richiederebbe quantità di tempo "estreme" o comporterebbe altri costi significativi, dovresti valutare tali costi con i benefici previsti di creare impegni più puliti.

In base alle informazioni che hai fornito, sceglierei l'opzione 1. Forse dovresti impostare dei promemoria che ti chiedono di confermare le modifiche?

Prototipazione e riscrittura

Un'altra considerazione da tenere a mente, soprattutto alla luce della tua nota sull'essere l'unico programmatore, e il mio sospetto che tu stia lavorando su una base di codice relativamente nuova, è che probabilmente è bene sviluppare abitudini diverse rispetto a commettere cambiamenti per quando stai prototipando un nuovo codice rispetto a mantenere o estendere il codice esistente. Probabilmente non c'è una divisione terribilmente netta tra i due, ma penso che sia ancora una distinzione utile.

Quando stai prototipando un nuovo codice, esegui il commit ogni volta che desideri salvare le modifiche, quasi certamente in un ramo, ma forse in un progetto separato. O forse anche solo lavorare al di fuori del controllo della versione. Puoi invece concentrarti sulla raccolta di prove sulla fattibilità di varie ipotesi o progetti che stai prendendo in considerazione. Scrivo spesso piccoli prototipi utilizzando strumenti diversi, ad esempio LINQPad anziché Visual Studio per codice C #.

Quando hai convalidato una particolare ipotesi o disegno, riscrivilo nel tuo progetto principale, idealmente in un ramo, e fai i piccoli, significativi impegni che aiuteranno meglio la comprensione degli altri (incluso il tuo futuro) sulla natura dei cambiamenti stai facendo.


1
Buona risposta; Kenny hai un buon articolo o altra base di conoscenza da collegare a dettagli più specifici sulla prototipazione? La mia versione del prototipo è "schizzo su notebook o su lavagna"
durron597,

@ durron597, non riesco a pensare a nessun link (neanche a cercarlo) dalla cima della mia testa. Ho giocato con abbastanza linguaggi di programmazione interpretati (e compilati dinamicamente) che non pensavo nemmeno che l'idea di "prototipazione" potesse essere nuova! E ho riscritto così tanti programmi C, C ++ e Java (ancora e ancora) che non pensavo che potesse essere insolito, o almeno romanzo per alcuni.
Kenny Evitt,

12

Sebbene l'unica risposta ragionevole sia quella di non rompere mai il bagagliaio , alcune volte non è possibile. Ad esempio, svn può interrompere il commit se commetti troppo (forse un'opzione o una funzione, non ne sono sicuro). In questi casi speciali, fai il check-in a pezzi. Dato che sei un singolo programmatore, non disturberà nessuno.

Pertanto, sceglierei l'opzione 1. Se non possibile, quindi l'opzione 2.

L'opzione 3 richiede molto sforzo e semplicemente non ne vale la pena.


1
o tagga le versioni non compilanti come "NON COMPILARE"
maniaco del cricchetto

2
@ratchetfreak: immagino che un "tag" in SVN non sia di grande aiuto, poiché i tag non funzionano come "commenti" sul trunk.
Doc Brown,

@DocBrown Volevo dire aggiungerlo al messaggio di commit
ratchet maniaco

5
@ratchetfreak Lo farei come "PARTE X / N: verifica in ABC - DOESNT COMPILE"
BЈовић

L'opzione 3 non richiede molti sforzi. Un'altra risposta spiega come farlo rapidamente e facilmente usando git add --patche git stash. La situazione sembra difficile solo a causa di strumenti e conoscenze obsoleti di controllo del codice sorgente.
Ron MacNeil,

7

Prova a suddividerlo in commit più piccoli che probabilmente non verranno compilati, poiché i file hanno più correzioni, modifiche, nomi di metodi aggiuntivi, ecc.

Quando mi sono trovato in una situazione simile ho usato la seguente tecnica:

  1. Aggiungi solo il codice rilevante per una particolare funzionalità: git add --patch
  2. Stash tutte le altre modifiche: git stash save --keep-index
  3. Esegui test / prova a compilare
  4. Commettere modifiche se tutto è a posto, altrimenti vai a 1

Non ho familiarità con SVN, quindi non so se questo sia applicabile alla tua situazione specifica, ma la base dovrebbe essere la stessa: isolare piccole parti di codice e testarle individualmente.


Mi piace, ma sfortunatamente una delle tante cose nella mia lista di cose da fare (ce ne sono molte quando sei l'unico tecnico in un'azienda) è passare da SVN a git, e non ci sono ancora riuscito .
durron597,

1
Dal momento che non sono abbastanza da usare --patch, uso Annulla in vari riquadri dell'editor, per arrivare a stati di lavoro precedenti e impegnarli. Quindi rifaccio per il prossimo commit. A causa della tentazione di apportare piccole aggiunte al codice in uno stato Undone, eseguo sempre un backup prima di iniziare questo processo!
joeytwiddle,

Con git puoi anche aggiungere in modo interattivo (aggiungi -i) prima di eseguire il commit e successivamente ramificare per convalidare i tuoi commit in modo indipendente.
riezebosch,

3

Che ne dici dell'opzione 4: esegui il backup dello stato corrente del tuo repository in una posizione temporanea, ripristina il repository allo stato originale, fai un elenco di tutte le modifiche che hai fatto (puoi ancora guardare il backup temporaneo), quindi reimplementa manualmente (e compila e testali!) come commit separati.

Questo dovrebbe essere più semplice, poiché hai già scritto il codice, è solo un po 'di capire quali parti copiare e incollare dal backup temporaneo.

Dopo aver reimplementato ogni modifica in modo pulito e assicurato in tal modo che i commit siano autonomi, di piccole dimensioni e compilati, è possibile eliminare il backup temporaneo e tutto sarà quasi esattamente come (tranne l'ora / la data dei commit) sarebbe stato se l'avessi fatto dall'inizio.


Questo è solo un modo di fare l'opzione n. 3. Probabilmente il modo migliore, vero, ma richiede ancora molto tempo.
durron597,

C'erano 149 righe di aggiunta / eliminazione / invio di messaggi quando ho eseguito il commit di grandi dimensioni. È almeno mezza giornata per farlo.
durron597,

@ durron597 Non sono d'accordo, penso che questo sia diverso dal n. 3. Per quanto riguarda 149 righe, quanto apprezzi una cronologia di commit pulita? Vale la pena spendere mezza giornata? Ad ogni modo, non è come se gli altri metodi non richiedessero di capire quale linea dovrebbe essere in quale commit, quindi dovrai passare attraverso le 149 linee in entrambi i modi. La differenza nel tempo sarà piccola.
Superbo

Eh. Ho abbastanza esperienza per sapere di usare il controllo versione, ma non abbastanza per averlo mai salvato il mio culo :) Quindi i motivi pratici per fare le cose sono ancora un po 'accademici, se sai cosa intendo.
durron597,

Non è necessario eseguire il backup dell'intero repository . È possibile effettuare un commit di "backup", quindi eseguire il rollback di HEAD con git reset HEAD~. Il tuo commit rimarrà attivo git reflogse deciderai di averne bisogno in seguito. Potresti persino spostare un ramo (e poi tornare al ramo funzionante) prima di eseguire il ripristino, per dare un nome al tuo "backup". Elimina il ramo in seguito se non ti serve. Modifica: mi dispiace non aver realizzato che OP è su svn!
joeytwiddle,

3

Sei l'unico programmatore; fai un unico check-in massiccio che descriva in dettaglio le parti importanti di ciò che hai fatto.

È probabile che esegua il rollback di "parti" di ciò che hai fatto? In caso contrario, procedere assolutamente con l'opzione 1.

Esistono un paio di motivi per controllare il codice in un sistema di controllo della versione. E TUTTI, quando sei l'unico sviluppatore, ruotano intorno alla sicurezza - vale a dire, se sbagli, la macchina muore o qualsiasi altra cosa, puoi sempre tornare all'ultimo checkpoint.

È improbabile che un programmatore che entra nel progetto in seguito voglia tornare a una versione che non viene compilata. Quindi, IMHO, l'opzione 2 è follia.

L'opzione 3 sembra un tale spreco di tempo, che se fossi il tuo capo e ti vedessi perdere ore facendo questo, ti farei una piccola chiacchierata con te su quanto vale il tuo tempo.

Per iterare: controllando il tuo codice stai coprendo / salvando il culo in caso di guasto sulla tua macchina. Tutto il resto, in una squadra individuale, è una vetrina.


1
Il rollback non è l'unico motivo per utilizzare piccoli commit. Non è nemmeno una ragione particolarmente buona. Il motivo principale è essere in grado di vedere quando e perché è stata introdotta una modifica e di facilitare la risoluzione dei problemi di fronte a un problema di origine sconosciuta. Un altro programmatore che entra nel progetto in seguito quasi certamente incontrerà almeno occasionalmente righe di codice che lo fanno andare "WTF" e fare riferimento al commit in cui è stato scritto o modificato per ultimo. Se quel commit è un commit gigante che cambia 500 cose, è impossibile ottenere qualsiasi informazione utile dalla storia.
Aaronaught

Per inciso, questo è il motivo per cui i team che usano Git generalmente odiano i merge merge e invece richiedono / richiedono ribassi; unione commette interruzioni bisecte altre tecniche comunemente usate per isolare i problemi, perché così tante modifiche sono racchiuse in un unico impegno.
Aaronaught

1
A livello personale, sono d'accordo che non dovresti fare grandi commit a meno che tu non stia cambiando radicalmente una base di codice ... a quel punto dovresti comunque diramarla. Tuttavia stiamo parlando di un singolo programmatore che ha funzionato essenzialmente disconnesso e ora sta cercando di tornare a fare la cosa giusta. In tal caso, credo che sia preferibile un grande commit.
NotMe

1
@Aaronaught Aggiungo che 3 mesi dopo puoi costituire un "altro programmatore".
Maciej Piechotka,

1
Devo anche essere in disaccordo con la ramificazione come strategia praticabile per cambiamenti architettonici o altri cambiamenti "distruttivi". Questo porta solo a un incubo di conflitti di unione e bug post-fusione. A lungo termine è molto, molto meno doloroso, trovare un modo per spezzare il cambiamento principale in cambiamenti più piccoli e compatibili con le versioni precedenti o, nel peggiore dei casi, usare ciò che Fowler, Humble e gli altri chiamano Branch Per astrazione (che in realtà non è affatto un ramo). Entrambe queste strategie implicano impegni piccoli e mirati.
Aaronaught,

2

La mia regola è: nessun check-in senza una seria revisione del codice. Se sono da solo, dovrò rivedere il codice da solo, ma sarà rivisto. Sembra che tu abbia una serie di modifiche al codice che qualcun altro non potrebbe rivedere, quindi non puoi esaminarlo tu stesso (rivedere il tuo codice è più difficile e richiede più disciplina, perché fai automaticamente il presupposto sbagliato che il tuo codice sia corretto ).

La regola totalmente infrangibile di tutti è: non effettuare mai il check-in del codice che non viene nemmeno creato ed evitare seriamente il check-in del codice che non funziona.

Soluzione: copia il codice modificato, torna al punto originale. Unisci una modifica alla volta nel codice originale, esaminalo, testalo, controllalo. Con il metodo di programmazione che hai descritto, sei obbligato a trovare alcuni bug gravi in ​​quel modo.

È anche un buon modo per allenarsi con buone abitudini di programmazione.


Questo è logicamente la stessa cosa della risposta basata su Git sopra ( git add --patche git stash) e un buon esempio di uno scenario che i moderni DVCS possono gestire facilmente, ma i sistemi più vecchi no.
Ron MacNeil,

1

Penso che ti stia preoccupando troppo. Se sei l'unico programmatore e non hai una scheda tecnica su cui lavorare, dipende da te quello che fai. Suppongo che nessuno ti punirà per aver commesso un grosso commit, quindi gli unici problemi che incontrerai sono tecnologici, come non essere in grado di ripristinare le modifiche ai singoli file all'interno del commit. Dal momento che in questo momento hai il controllo esclusivo del repository, non dovrebbe essere una grande preoccupazione.

C'è una linea da tracciare tra pragmatismo e dogmatismo. Quello che hai fatto non sarebbe una buona idea in una squadra e probabilmente non dovrebbe essere ripetuto andando avanti, ma nella tua situazione vorrei solo presentare il grande impegno.


1
questo non sembra aggiungere nulla di sostanziale rispetto a quello che era già stato pubblicato nelle precedenti 12 risposte
moscerino del

-1

Il problema non è nei lunghi ritardi tra i commit ma nel fatto che il codice viene mantenuto in uno stato non compilabile troppo a lungo. Prima di tutto qual è la tua definizione di "lungo"? Per alcune persone 5 minuti per lo stato di transizione è troppo, ma alcuni possono lucidare il loro codice per giorni senza nemmeno provare a eseguire il compilatore.

In realtà non importa: ciò che conta è che hai perso il controllo del tuo codice, il tuo codice è diventato ingestibile. Questo è normale, significa solo che hai un debito tecnologico ed è tempo di pensare al refactoring. Quindi sei frustrato? Il codice non viene compilato, non hai nemmeno i test unitari? Come puoi pensare al refactoring in questo caso? Nessun problema. Termina la tua "codifica da cowboy" e inizia a pulirla. Idealmente, prova a scrivere alcuni test. Non hai tempo per quello? Ok, inizia da piccoli miglioramenti.

Alcune modifiche non richiedono test. Cambia il nome della variabile per renderlo più adatto, sposta il codice ripetuto in una funzione separata, ecc ... Avrai una migliore idea del tuo codice. Dopodiché puoi fare grandi cambiamenti. Ancora una volta, prova a scrivere dei test, se possibile. Rendi gestibile il tuo codice.

Successivamente vedrai che il prossimo cambiamento non ti richiederà "troppo tempo" (qualunque cosa significhi).


2
Non ha detto che avrebbe mantenuto il codice incompatibile per molto tempo. Il codice nel repository non è stato modificato per molto tempo, ma è ancora compilabile. Il codice nella sua copia di lavoro è stato aggiornato frequentemente ma non è stato eseguito il commit. Nulla nella domanda suggerisce che il suo codice potrebbe richiedere il refactoring - la "codifica da cowboy" qui si riferisce al suo flusso di lavoro SCM, non alla reale qualità del codice
Idan Arye,

@IdanArye Dalla domanda originale ...Try to break it into smaller commits that likely won't compile...Se qualcosa ti impedisce di commettere il tuo codice di quanto sia già una buona cantata quel codice è difficile da gestire. "Commit" è solo uno dei modi per perseverare nel tuo lavoro. Possiamo pensare a casi più estremi: "se qualcosa mi impedisce di salvare il file sorgente". Quindi cosa potrebbe essere? Immagino sia la paura dei tuoi stessi cambiamenti. Perché può essere? ... Immagino tu abbia capito il punto
AlexT,

2
Per me sembra più che ciò che gli ha impedito di commettere è stata la semplice pigrizia.
Idan Arye,

@IdanArye Hai ragione sotto tutti gli aspetti. Questo plus non fa abbastanza TDD, che è un problema separato.
durron597,

@AlexT considera uno scenario in cui correggi due bug e uno di essi richiede un metodo di nuova concezione. Se hai commesso correttamente, correggi un bug, commetti, quindi correggi l'altro bug. In caso contrario, quando si esegue il commit, è necessario includere entrambe le modifiche nello stesso commit oppure eseguire il commit della prima correzione di bug con le modifiche per la seconda, tranne per il fatto che la versione di commit non ha il nuovo metodo chiamato e quindi non compilare.
durron597,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.