In che modo `git pull` ha mangiato i miei compiti?


53

Mi sento come un bambino nell'ufficio del preside che spiega che il cane ha mangiato i compiti la sera prima che fosse dovuto, ma sto fissando un bug pazzo di perdita di dati in faccia e non riesco a capire come sia successo. Vorrei sapere come Git potrebbe mangiare il mio repository intero! Ho passato molte volte lo strizzatore e non ha mai battuto ciglio. L'ho usato per dividere un repository Subversion da 20 Gig in 27 repository git e filtrare il foo da loro per districare il casino e non ha mai perso un byte su di me. Il reflog è sempre lì su cui ripiegare. Questa volta il tappeto è sparito!

Dal mio punto di vista, tutto ciò che ho fatto è stato eseguito git pulle ha rovinato il mio intero repository locale. Non intendo dire che "ha incasinato la versione estratta" o "il ramo in cui mi trovavo" o qualcosa del genere. Voglio dire, l'intera cosa è sparita .

Ecco una schermata del mio terminale all'incidente:

schermata dell'incidente

Lascia che ti accompagni attraverso quello. Il mio prompt dei comandi include dati sul repository git corrente (usando l'implementazione vcs_info di prezto) in modo da poter vedere quando il repository git è scomparso. Il primo comando è abbastanza normale:

  » caleb » jaguar » ~/p/w/incil.info » ◼  zend ★ »
❯❯❯ git co master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

Lì puoi vedere che ero sul ramo 'zend' e ho controllato il maestro. Fin qui tutto bene. Vedrai nel prompt prima del mio prossimo comando che ha cambiato correttamente i rami:

  » caleb » jaguar » ~/p/w/incil.info » ◼  master ★ »
❯❯❯ git pull
remote: Counting objects: 37, done.
remote: Compressing objects: 100% (37/37), done.
remote: Total 37 (delta 25), reused 0 (delta 0)
Unpacking objects: 100% (37/37), done.
From gitlab.alerque.com:ipk/incil.info
 + 7412a21...eca4d26 master     -> origin/master  (forced update)
   f03fa5d..c8ea00b  devel      -> origin/devel
 + 2af282c...009b8ec verse-spinner -> origin/verse-spinner  (forced update)
First, rewinding head to replay your work on top of it...
>>> elapsed time 11s

E proprio così non c'è più. L'indicatore del tempo trascorso viene emesso prima del prompt successivo se sono trascorsi più di 10 secondi. Git non ha dato alcun risultato oltre l'avviso che stava riavvolgendo per riprodurre. Nessuna indicazione che sia finita.

Il prossimo prompt non include dati su quale ramo ci troviamo o sullo stato di git.

Non accorgendomi che era fallito, ho cercato inconsapevolmente di eseguire un altro comando git solo per sentirmi dire che non ero in un repository git. Nota che il PWD non è cambiato:

  » caleb » jaguar » ~/p/w/incil.info »
❯❯❯ git fetch --all
fatal: Not a git repository (or any parent up to mount point /home)
Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).

Dopo questo uno sguardo in giro ha mostrato che ero in una directory completamente vuota. Niente. Nessuna directory '.git', niente. Vuoto.

Il mio git locale è alla versione 2.0.2. Ecco un paio di bocconcini dal mio git config che potrebbero essere rilevanti per capire cosa è successo:

[branch]
        autosetuprebase = always
        rebase = preserve
[pull]
        rebase = true
[rebase]
        autosquash = true
        autostash = true
[alias]
        co = checkout

Ad esempio, ho git pullimpostato di fare sempre un rebase anziché un'unione, quindi una parte dell'output sopra è normale.

Posso recuperare i dati. Non credo che ci fossero oggetti git diversi da alcuni oggetti non importanti che non erano stati spinti in altri repository, ma mi piacerebbe sapere cosa è successo .

Ho controllato per:

  • Messaggi in dmesg o nel journal di systemd. Niente di rilevante neanche lontanamente.
  • Non vi è alcuna indicazione di guasto dell'unità o del file system (LVM + LUKS + EXT4 sembrano tutti normali). Non c'è nulla in lost + found.
  • Non ho fatto altro. Non c'è nulla nella storia che non sto mostrando sopra, e nessun altro terminale è stato usato in questo periodo. Non ci sono rmcomandi in giro che potrebbero essere stati eseguiti nel CWD sbagliato, ecc.
  • Frugare in un altro repository git in un'altra directory non mostra alcuna anomalia apparente durante l'esecuzione di git pulls.

Cos'altro dovrei cercare qui?


4
@Patrick Come ho già spiegato nella domanda, no .gitnon esiste. Niente fa: quella che era la directory root di Git non contiene nulla.
Caleb,

2
@Alexander L'operazione pull è normale (altro che essere un rebase piuttosto che una fusione). L'avviso su un aggiornamento forzato indica che il repository da cui sto estraendo ha avuto una spinta forzata che lo ha ripristinato da una posizione diversa rispetto a quella dell'ultimo repository locale in cui l'ho visto. Questo è normale perché sto sincronizzando materiale attivamente sviluppato e spesso riformulato tra i miei computer, non una filiale pubblica che altri sviluppatori vedranno.
Caleb,

3
@Caleb il prompt della shell include l'indicazione del ramo git, il che significa che la formazione di PS1 include comandi git non esposti nel registro. Possono principalmente cambiare l'immagine e possono essere la fonte del problema. È necessario aggiornare la domanda descrivendo con precisione come viene formato il prompt della shell, quali comandi vengono eseguiti per ottenere un ramo corrente e riconsiderare come potrebbero rovinare il repository.
Netch

2
@Caleb Dovresti davvero chiedere sulla mailing list di sviluppo di git; Potresti scriverlo come una segnalazione di bug, o semplicemente chiedere in modo informale - è lo stesso comunque. Ci sono alcuni sviluppatori che conoscono git in modo impressionante - probabilmente possono dire per intuizione cosa sarebbe potuto succedere. (In caso contrario, seguiranno semplicemente la discussione in silenzio.) E sanno se è successo prima. (Segnalandolo c'è il modo "ufficiale" di segnalare bug per git)
Volker Siegel,

7
@Wildcard In realtà ho avuto intenzione di mettere insieme una risposta a questo mentre in realtà ho capito cosa è successo. Il sistema si era recentemente spento e la rete era rimasta fuori per giorni prima di andare in sospensione. Da qualche parte in quel processo avevo lasciato in esecuzione un processo pacman che stava cercando di aggiornare qualcosa sul sistema. Per farla breve, risulta che glibc è stato aggiornato e il binario git è stato sovrascritto. A causa del modo in cui si biforcò, un'istanza finì per essere diversa dall'altra e si mangiarono a vicenda. La directory era davvero vuota (non solo appar
Caleb,

Risposte:


6

Sì, githo mangiato i compiti. Tutto.

Ho creato ddun'immagine di questo disco dopo l'incidente e in seguito ne ho fatto un casino. Ricostruendo la serie di eventi dai registri di sistema, deduco che quello che è successo è stato qualcosa del genere:

  1. Un comando di aggiornamento del sistema ( pacman -Syu) era stato emesso giorni prima di questo incidente.
  2. Un'interruzione di rete estesa significa che è stato lasciato tentare nuovamente di scaricare i pacchetti. Frustrato per la mancanza di Internet, avrei messo il sistema in stato di stop e sarei andato a letto.
  3. Giorni dopo il sistema è stato svegliato e ha iniziato a trovare e scaricare nuovamente i pacchetti.
  4. Il download del pacchetto è terminato poco prima che mi capitasse di fare casino con questo repository.
  5. L' installazione di glibc di sistema è stata aggiornata dopo git checkoute prima di git pull.
  6. Il gitbinario è stato sostituito dopo l' git pullavvio e prima che finisse.
  7. E il settimo giorno, gitriposava da tutte le sue fatiche. E cancellò il mondo così tutti gli altri dovevano riposare.

Non so esattamente quali condizioni di gara si siano verificate che lo hanno reso possibile, ma lo scambio di file binari nel mezzo di un'operazione non è certamente piacevole né una condizione verificabile / ripetibile. Di solito una copia di un binario in esecuzione è archiviata in memoria, ma gitè strana e qualcosa sul modo in cui ricompare le versioni di se stesso sono sicuro che ha portato a questo pasticcio. Ovviamente sarebbe dovuto morire piuttosto che distruggere tutto, ma è quello che è successo.


1
git potrebbe non essere riuscito perché git è stato creato usando comandi differend, invece di un singolo binario. Viene eseguito un semplice git pull git-fetch, git-rebaseoppure git-mergeegit gc
Ferrybig il

2

Probabilmente non riuscendo a definire il percorso del file da eliminare.

Il tuo caso mi ha ricordato un bel giorno in cui il mio remove(path)metodo casalingo ha cercato di rimuovere la cartella principale perché il parametro dato era una stringa vuota che il sistema operativo ha corretto (!) Come cartella principale.

Potrebbe trattarsi di un bug git simile. Tale che:

  1. Il comando Rebase voleva eliminare un file come remove(project_folder + file_path)(codice pseudo)
  2. In qualche modo file_pathera vuoto al momento.
  3. Comando valutato come qualcosa del genere remove(project_folder)

1

Per fortuna, puoi risolverlo con il seguente comando:

git reset --hard ORIG_HEAD  

Quando iniziano potenziali cambiamenti pericolosi, git blocca il tuo stato attuale in ORIG_HEAD. Con esso puoi annullare un'unione o un rebase.

Manuale Git: annullamento di un'unione


4
Non credo che tu abbia letto l'intera domanda. Questo tipo di correzione è completamente fuori discussione perché non ci sono metadati git . Fare un reset come questo richiede una directory .git esistente e alcuni oggetti in essa funzionanti. Non ho niente. Non è solo una directory di lavoro incasinata, non è più un repository di alcun tipo.
Caleb,

Ah, le mie scuse. È molto insolito. Se git repo non c'è più, suppongo che non ci sarà modo di recuperare a meno che non si stiano eseguendo l'ombreggiatura dei file in Linux e si disponga dei backup fs dei file. Eliminerò la mia risposta poiché è irrilevante.
Routhinator,

Sì, lo so che è un problema insolito (e ho i backup). La mia domanda qui è come è andato storto ... dove cercare il bug in git o il mio driver del file system o qualsiasi altra cosa avrebbe potuto funzionare per mangiare una directory nel mezzo di un'operazione come questa.
Caleb,

Sono anche molto curioso. Odio che succeda qualcosa del genere ai miei repository.
Routhinator,

-1

Sembra che qualcuno abbia corso git push --forcesu questo repository e tu abbia annullato quei cambiamenti. Prova a clonare il repository fresco, che dovrebbe riportarti di nuovo in uno stato di lavoro pulito.


1
La spinta forzata ha riformulato l'ultima manciata di commit. Non è quello che ho tirato giù (la directory di lavoro non è più una directory di lavoro!) E anche se stesse ri-clonando non avrebbe alcun senso.
Caleb,

4
Non credo che puoi rimuovere la .gitdirectory di qualcuno con una spinta forzata
Grzegorz,
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.