Git può ignorare una riga specifica?


115

Sto usando git per sincronizzarmi con phonegap durante il test sul browser nativo del telefono. Come tale ho la seguente riga:

var isPhoneGap = false;

Ovviamente lo cambio durante la compilazione, ma c'è un modo in cui posso impostare git per ignorare questa riga o devo andare e metterlo nel suo file e ignorarlo in quel modo?

Sto usando Gitx e il terminale su OSX 10.6.


@ user494461: filtri Git è il modo per farlo: stackoverflow.com/a/16244970/520162
Eckes

1
Non riesci a rilevare l'ambiente e utilizzare un file di configurazione dell'ambiente?
exussum

In breve: No. Ma ho scritto uno script per il preprocessore che cerca un certo codice commentato e lo rimuove prima della pubblicazione in git.
franklin

Risposte:


104

Se il tuo file è di un tipo specifico, puoi dichiarare un driver di filtro dei contenuti , che puoi dichiarare in un .gitattributesfile (come presentato in "Espansione parola chiave" di " Attributi Git "):

http://git-scm.com/figures/18333fig0702-tn.png

*.yourType filter=yourFilterName

(puoi anche impostare quel filtro per un file specifico , se lo desideri)

Strumento:

  • yourFilterName.smudge(attivato git checkout) e

    git config --global filter.yourFilterName.smudge 'sed "s/isPhoneGap = .*/isPhoneGap = true/"'
    
  • yourFilterName.clean(attivato git add)

    git config --global filter.yourFilterName.clean 'sed "s/isPhoneGap = .*/isPhoneGap = false/"'
    

Il tuo file sembrerebbe invariato su git status, ma la sua versione estratta avrebbe il valore giusto per isPhoneGap.


1
Grazie per questo. ha funzionato. Sai come creare git diff or git status`, ignorando i filtri? Quindi posso ancora vedere cosa c'è di diverso? Il mio caso d'uso è per i log di debug ... che alla fine voglio eliminare ... @jthill @VonC
timh

1
@timh se il filtro funziona, git status o git diff non dovrebbero mostrare nulla.
VonC

1
è un peccato che non ci sia un modo più semplice in GIT. git ignore <filename> <linenumber> sarebbe così utile!
kiedysktos

22
@kiedysktos linoumber? E se il numero di riga cambia?
VonC

Funzionava benissimo, ma gli utenti di Windows fanno attenzione, gitconfig è molto esigente con i caratteri che vuole contenere, quindi quando si provano alcune espressioni regolari semi-esotiche si possono avere problemi. Ho finito per mettere le mie chiamate sed in un file helper.sh separato che ho chiamato dal mio gitconfig sh ".git/helper.sh"assicurandomi di passare tutti i parametri a sed con "$@"(presumo sia passato solo il percorso file).
ohaal

43

Puoi usare

git update-index --assume-unchanged [file]

per ignorare le modifiche di un file di cui non vuoi tenere traccia. Uso questa soluzione quando ho bisogno di avere un file nel repository ma questo file ha alcune parti che cambiano che non ho bisogno di tenere sempre traccia.

Quando il file ha modifiche importanti, devi farlo:

git update-index --no-assume-unchanged [file]

Inoltre, vedere il documento Git update-index per il --[no-]assume-unchangedparametro.

Quando vengono specificati questi flag, i nomi degli oggetti registrati per i percorsi non vengono aggiornati. Invece, queste opzioni impostano e annullano il bit "presumi invariato" per i percorsi. Quando il bit "presumi invariato" è attivo, git smette di controllare i file dell'albero di lavoro per eventuali modifiche, quindi devi annullare manualmente il bit per dire a git quando cambi il file dell'albero di lavoro.


2
In questo modo verrà ancora recuperata la nuova versione quando eseguo git pull?
Saad Rehman Shah

1
@Caffeine quando esegui git pull ottieni l'ultima versione che è stata confermata, questa sarà l'ultima prima di cambiare il file in "--assume-unchanged".
Carlos

1
Credo --skip-worktreesia un'opzione migliore per la maggior parte degli scopi. stackoverflow.com/a/39583010/4233593
Jeff Puckett,


3
questo ignora gli aggiornamenti all'intero file, non una riga specifica
nikoss

6

Gitx dovrebbe consentirti di eseguire il commit o ignorare le singole righe (potresti già saperlo), ma dovresti farlo ogni volta che effettui il commit. Penso che sarebbe meglio avere un file di configurazione per destinazione di distribuzione (è possibile eseguire la versione di quelli) e alcuni parametri di runtime per come si avvia il server (come ./myserver --config=whatever.js).


5

Continuando https://stackoverflow.com/a/20574486/4935114 , @Mike ha proposto di creare un pre-commithook che sarà grepnei file staged per le linee che si potrebbe voler ignorare. L'hook controlla se quelle linee sono state messe in scena. Se è così, è echoun avvertimento ed è exitcon codice 1così il processo di commit non continuerà.

Ispirato dalla risposta di @Mike , mi sono ritrovato a usare forse una versione migliorata del suo hook che automaticamente reset s (con la -pbandiera) la linea specifica che vogliamo ignorare.

Non sono sicuro che questo hook funzionerà per una situazione in cui hai molti file con questa riga da ignorare, ma questo pre-commithook cerca una modifica in questa riga in un file specifico buildVars.java. Lo script hook sembrava così quando l'ho testato sulla mia macchina.

#!/bin/sh

# this hook looks for lines with the text `var isPhoneGap = false;` in the file `buildVars.java` and it resets these lines to the previous state before staged with `reset -p`

if [[ $(git diff --no-ext-diff --cached buildVars.java | grep --count -e "var\ isPhoneGap[\ ]*=[\ ]*") -ne 0 ]]; then
    cat <<EOW
WARNING: You are attempting to commit changes which are not supposed to be commited according to this \`pre-commit\` hook
This \`pre-commit\` hook will reset all the files containing this line to it's previous state in the last commit.
EOW
    echo /$'\n'isPhoneGap$'\n'y$'\n'q | git reset -p
    # BONUS: Check if after reseting, there is no actual changes to be commited and if so, exit 1 so the commit process will abort.
    if [[ $(git diff --no-ext-diff --cached | wc -l) -eq 0 ]]; then
        echo there are no actual changes to be commited and besides the change to the variable \'isPhoneGap\' so I won\'t commit.
        exit 1
    fi
fi

Spiegazione

Quello che ho fatto è stato l'eco di una sequenza di controllo che cerca la regex isPhoneGapdurante un resetprocesso interattivo . Emulando così un utente che preme /per cercare isPhoneGap, preme yquando gli viene chiesto se vuole scartare questa patch e infine preme qper uscire dall'interattivo reset.

Il processo di patch inverso interattivo è documentato qui: https://git-scm.com/docs/git-add#git-add-patch


NOTA: lo script precedente presuppone che la variabile interactive.singleKeysia false. Se hai configurato il tuo su true, rimuovine qualsiasi $'\n'dal echocomando subito dopo l'avviso.


3

Ecco come puoi farlo con i filtri git :

  1. Crea / Apri file gitattributes:
    • <root del progetto> /. gitattributes (verrà eseguito il commit nel repo)
      OPPURE
    • <root del progetto> /. git / info / attributes (non verrà eseguito il commit nel repository)
  2. Aggiungi una riga che definisce i file da filtrare:
    • *.rb filter=gitignore, ovvero esegui il filtro denominato gitignoresu tutti i *.rbfile
  3. Definisci il gitignorefiltro nel tuo gitconfig:
    • $ git config --global filter.gitignore.clean "sed '/#gitignore$/'d", ovvero eliminare queste righe
    • $ git config --global filter.gitignore.smudge cat, ovvero non fare nulla quando si estrae il file dal repository

Note:
ovviamente, questo è per i file ruby, applicato quando una riga termina con #gitignore, applicato globalmente in ~/.gitconfig. Modificalo come ti serve per i tuoi scopi.

Avvertimento!!
Questo lascia il tuo file di lavoro diverso dal repository (ovviamente). Qualsiasi check-out o ribasamento significherà che queste linee andranno perse! Questo trucco può sembrare inutile poiché queste righe vengono ripetutamente perse durante il check out, il rebase o il pull, ma ho un caso d'uso specifico per utilizzarlo.

Solo git stash save "proj1-debug" mentre il filtro è inattivo (disabilitalo temporaneamente gitconfigo qualcosa del genere). In questo modo, il mio codice di debug può sempre essere git stash applyaggiunto al mio codice in qualsiasi momento senza timore che queste righe vengano salvate accidentalmente.

Ho una possibile idea per affrontare questi problemi, ma cercherò di implementarla un'altra volta.

Grazie a Rudi e jw013 per aver menzionato filtri git e gitattributes.


2

Un driver di filtro dei contenuti non è una buona soluzione. Potresti essere in grado di nascondere questa riga da git status/ etc ma non viene davvero ignorata. Non appena si modifica il valore, la directory di lavoro verrà contrassegnata come sporca anche se la modifica potrebbe non essere visibile.

Se si desidera davvero che questa riga sia fuori dal controllo della versione, cambiarla in un argomento della riga di comando o inserirla in un file di inclusione o compilazione ignorato può essere l'unico mezzo pratico.


"Non appena si modifica il valore, la directory di lavoro verrà contrassegnata come sporca anche se la modifica potrebbe non essere visibile": non dovrebbe, se lo script pulito ripristina ancora il file nel suo contenuto originale.
VonC

Questo è quello che avevo pensato. Sto usando GitExtensions e mostrerà il file come modificato anche se il riquadro delle differenze è vuoto. Forse perché il filtro pulito non viene eseguito fino al check-in del file. Forse perché è msysgit, non git-git. IDK,
YMMV

1

Immagino che questo potrebbe essere qualcosa che emerge in più di una riga della tua fonte.

Penso che sarebbe più pulito avere un file .userbuildconfig di qualche tipo che includi e che i valori predefiniti vengano archiviati. Quindi puoi usare il suggerimento di Carlos per contrassegnare quel file come presunto invariato. In questo modo non vengono perse altre modifiche al file in cui è necessario controllare l'impostazione.

Ciò può consentire di regolare localmente le macro del preprocessore (o per java qualcosa di simile a questo https://stackoverflow.com/a/1813873/1270965 ).


-1

No. Puoi ignorare solo singoli file (e altro) poiché le righe in .gitignore corrispondono ai nomi dei file e non al contenuto dei file. Hai già menzionato la soluzione a questo, cioè ignora un singolo file che contiene quel contenuto che vuoi ignorare.


Sono d'accordo, nel mio caso era sufficiente e possibile includere semplicemente quel contenuto da un file ignorato. Quindi spostando tutte le impostazioni ignorabili. Là. Inoltre, ho creato una copia di quel file ignorato e l'ho aggiunto all'indice come riferimento, in modo che le informazioni su cosa ci sarà in quel file non andranno perse.
Urs
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.