Colpa della colpa - commetti precedenti?


391

È possibile vedere chi ha modificato una riga specifica prima del commit segnalato da git blame, come una cronologia di commit per una determinata riga?

Ad esempio, eseguo quanto segue (sul superbo uncrustifyprogetto):

$ git blame -L10,+1 src/options.cpp
^fe25b6d (Ben Gardner 2009-10-17 13:13:55 -0500 10) #include "prototypes.h"

Come posso sapere chi ha modificato quella riga prima del commit fe25b6d? E chi l'ha modificato prima di quel commit?


7
se il motivo per cui stai cercando commit precedenti sono le modifiche agli spazi bianchi usa l' -wopzione. C'è anche -Mper il codice spostato / copiato
brita_

Per cercare tutti i commit che implicano una determinata parola, vedi la mia sceneggiatura qui sotto
VonC

Ecco uno script utile per aggiungere questa funzionalità su github greasyfork.org/en/scripts/…
Aaron Hoffman,

3
Non sono sicuro di come apparisse github quando @AaronHoffman ha pubblicato, ma ora è molto facile incolpare - e ottenere le colpe per le versioni precedenti - in github .
ruffin,

Risposte:


389
git blame -L 10,+1 fe25b6d^ -- src/options.cpp

È possibile specificare una revisione per git blame a cui guardare indietro a partire da (anziché il valore predefinito di HEAD); fe25b6d^è il genitore di fe25b6d.


107
Puoi ottenere una cronologia completa, senza dover reinserire il comando più volte con hash diversi?
Anders Zommarin,

13
Non credo che Git abbia un modo integrato per ottenere ogni colpa che ha toccato un numero di linea (che tipo di senso ha senso, dal momento che una determinata linea potrebbe non avere un numero di linea coerente nella storia di un file a causa di inserimenti ed eliminazioni di linee).
Ambra

17
@Amber: Abbastanza sicuro che tu abbia ragione sul fatto che la funzione non esiste, ma sembra che potrebbe essere implementata in modo ingenuo, semplicemente facendo ciò che farebbe un essere umano: incolpalo una volta, prendi le informazioni riportate, incolpa che , e così via.
Cascabel,

15
git gui rende abbastanza facile controllare la cronologia di una linea poiché le versioni sono cliccabili.
Zitrax,

5
@shadyabhi --è comunemente usato come separatore negli argomenti della riga di comando - nel caso di Git, di solito è usato per separare cose come commit hash da un elenco di nomi di file.
Ambra

192

Puoi usare git log -L per visualizzare l'evoluzione di un intervallo di linee.

Per esempio :

git log -L 15,23:filename.txt

significa "traccia l'evoluzione delle righe da 15 a 23 nel file denominato nomefile.txt".


12
Questa è una risposta solida e affronta la domanda di Anders Zommarin sopra su come vedere le modifiche a linee specifiche nel tempo.
bigtex777,

4
Cordiali saluti: git log -L <start>, <end>: <file> richiede Git 1.8.4+ vedi: git-scm.com/docs/git-log#git-log--Lltstartgtltendgtltfilegt per le opzioni di sintassi
Neon

30

La risposta di Amber è corretta ma l'ho trovata poco chiara; La sintassi è:

git blame {commit_id} -- {path/to/file}

Nota: --viene utilizzato per separare l'albero-ish sha1 dai relativi percorsi di file. 1

Per esempio:

git blame master -- index.html

Riconoscimento completo ad Amber per aver saputo tutto! :)


1
Sono d'accordo con il tuo sentimento. Il sistema di commenti è tuttavia troppo limitato per presentare tutte le informazioni in modo chiaro. Ho aggiunto il contenuto di questa risposta in un commento; tuttavia, insisto per lasciare che questa risposta sia un luogo per un facile accesso.
ThorSummoner,

1
Dovrebbe essere un post separato o una modifica. Mi piace come una risposta separata.
Flimm,

27

Potresti voler dare un'occhiata:

git gui blame <filename>

Ti dà una bella visualizzazione grafica di cambiamenti come "git blame" ma con link cliccabili per riga, per passare ai commit precedenti. Passa il mouse sopra i collegamenti per visualizzare un popup con i dettagli del commit. Non i miei crediti ... l'ho trovato qui:

http://zsoltfabok.com/blog/2012/02/git-blame-line-history/

git guiè un'interfaccia grafica Tcl / Tc per git. Senza altri parametri avvia un'app grafica piuttosto semplice ma utile per eseguire il commit di file, hunk o anche singole righe e altri comandi simili come modifica, ripristina, push ... Fa parte della suite git stock. Su Windows è incluso nel programma di installazione. Su debian - non conosco altri sistemi * nix - deve essere installato separatamente:

apt-get install git-gui

Dai documenti:

https://git-scm.com/docs/git-gui

DESCRIZIONE

Un'interfaccia utente grafica basata su Tcl / Tk per Git. git gui si concentra sul consentire agli utenti di apportare modifiche al loro repository effettuando nuovi commit, modificando quelli esistenti, creando filiali, eseguendo fusioni locali e recuperando / spingendo in repository remoti.

A differenza di gitk, git gui si concentra sulla generazione del commit e sull'annotazione di singoli file e non mostra la cronologia del progetto. Fornisce tuttavia azioni di menu per avviare una sessione gitk dall'interno di git gui.

git gui è noto per funzionare su tutti i più diffusi sistemi UNIX, Mac OS X e Windows (sia con Cygwin che MSYS). Nella misura del possibile vengono seguite le linee guida specifiche dell'interfaccia utente del SO, rendendo git gui un'interfaccia abbastanza nativa per gli utenti.

COMANDI

colpa

Avvia un visualizzatore di colpe sul file specificato nella versione specificata (o directory di lavoro se non specificato).

del browser

Avviare un browser ad albero che mostra tutti i file nel commit specificato. I file selezionati tramite il browser vengono aperti nel visualizzatore di colpa.

citool

Avvia git gui e disponi di effettuare esattamente un commit prima di uscire e tornare alla shell. L'interfaccia è limitata a impegnare solo azioni, riducendo leggermente il tempo di avvio dell'applicazione e semplificando la barra dei menu.

versione

Visualizza la versione attualmente in esecuzione di git gui.


Non funziona per me. Posso fare clic sulla modifica su una determinata riga, ma ciò cambia la vista in modo che corrisponda a quel commit e la riga corrente ora mostra come this: ma come posso vedere la versione precedente della riga e quando è stata aggiunta?
BeeOnRope,

Questo è il caso d'uso che conosco di dove git gui è la soluzione migliore
cambunctious

17

Basandosi sulla risposta precedente, questo bash one-liner dovrebbe darti quello che stai cercando. Visualizza la cronologia delle colpe git per una particolare riga di un determinato file, attraverso le ultime 5 revisioni:

LINE=10 FILE=src/options.cpp REVS=5; for commit in $(git rev-list -n $REVS HEAD $FILE); do git blame -n -L$LINE,+1 $commit -- $FILE; done

Nell'output di questo comando, è possibile che venga visualizzato il contenuto della riga o il numero di riga visualizzato potrebbe persino cambiare, per un determinato commit.

Questo spesso indica che la linea è stata aggiunta per la prima volta, dopo quel particolare commit. Potrebbe anche indicare che la linea è stata spostata da un'altra parte del file.


5
Si noti che queste sono le ultime revisioni $ REVS in cui $ FILE è cambiato, anziché le ultime revisioni $ REVS in cui $ LINE è cambiato.
Max Nanasy,

A quale risposta ti riferisci?
Flimm,

Non mi ricordo più. Forse avrei potuto migliorare la risposta del mio futuro.
Will Sheppard,


11

Una soluzione davvero unica per questo problema sta usando git log:

git log -p -M --follow --stat - path / to / your / file

Come spiegato da Andre qui


1
Ho creato un alias per usare questo: git config --global alias.changes 'log -p -M --follow --stat --'e poi posso semplicemente digitaregit changes path/to/your/file
Tizio Fittizio

Questa è di gran lunga la risposta migliore ed esattamente quello che stavo cercando. Semplice ed elegante.
martedì

10

Se si utilizza Idea ID JetBrains (e derivati) è possibile selezionare più righe, fare clic con il tasto destro del mouse sul menu di scelta rapida, quindi Git -> Mostra cronologia per la selezione. Vedrai un elenco di commit che interessavano le linee selezionate:

inserisci qui la descrizione dell'immagine


Questo ha funzionato meglio delle altre risposte per me (usando IntelliJ). Ci è voluto un po 'per caricare tutte le revisioni ma valeva la pena aspettare.
Steve Chambers,

2

A partire da Git 2.23 puoi usare git blame --ignore-rev

Per l'esempio fornito nella domanda questo sarebbe:

git blame -L10,+1 src/options.cpp --ignore-rev fe25b6d

(tuttavia è una domanda trabocchetto perché fe25b6d è la prima revisione del file!)


1

Basandosi sulla risposta di Will Shepard, il suo output includerà righe duplicate per commit in cui non vi sono state modifiche, quindi è possibile filtrarle come segue (utilizzando questa risposta )

LINE=1 FILE=a; for commit in $(git rev-list HEAD $FILE); do git blame -n -L$LINE,+1 $commit -- $FILE; done | sed '$!N; /^\(.*\)\n\1$/!P; D'

Nota che ho rimosso l'argomento REVS e questo risale al commit root. Ciò è dovuto all'osservazione di Max Nanasy sopra.


1

Basandomi sulla risposta di DavidN e voglio seguire il file rinominato:

LINE=8 FILE=Info.plist; for commit in $(git log --format='%h%%' --name-only --follow -- $FILE | xargs echo | perl -pe 's/\%\s/,/g'); do hash=$(echo $commit | cut -f1 -d ','); fileMayRenamed=$(echo $commit | cut -f2 -d ','); git blame -n -L$LINE,+1 $hash -- $fileMayRenamed; done | sed '$!N; /^\(.*\)\n\1$/!P; D'

ref: mostra bene la cronologia dei nomi dei file nel log git


0

Uso questo piccolo script bash per guardare una storia di colpa.

Primo parametro: file da guardare

Parametri successivi: passato a git blame

#!/bin/bash
f=$1
shift
{ git log --pretty=format:%H -- "$f"; echo; } | {
  while read hash; do
    echo "--- $hash"
    git blame $@ $hash -- "$f" | sed 's/^/  /'
  done
}

Puoi fornire parametri di colpa come -L 70, + 10 ma è meglio usare la ricerca regex di git blame perché i numeri di riga in genere "cambiano" nel tempo.


0

Costruire sulla stangls 's risposta , ho messo questo script sul mio cammino (anche su Windows) come git-bh:

Ciò mi consente di cercare tutti i commit in cui è stata coinvolta una parola:

git bh path/to/myfile myWord

script:

#!/bin/bash
f=$1
shift
csha=""
{ git log --pretty=format:%H -- "$f"; echo; } | {
  while read hash; do
    res=$(git blame -L"/$1/",+1 $hash -- "$f" 2>/dev/null | sed 's/^/  /')
    sha=${res%% (*}
    if [[ "${res}" != "" && "${csha}" != "${sha}" ]]; then
      echo "--- ${hash}"
      echo "${res}"
      csha="${sha}"
    fi
  done
}
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.