Jak odczytać wyjście z git diff?
Strona podręcznika dla git-diff
jest dość długa i wyjaśnia wiele przypadków, które nie wydają się być konieczne dla początkujących. Na przykład:
git diff origin/master
7 answers
Przyjrzyjmy się przykładowi advanced diff z git history (w commit 1088261f w git.repozytorium git):
diff --git a/builtin-http-fetch.c b/http-fetch.c
similarity index 95%
rename from builtin-http-fetch.c
rename to http-fetch.c
index f3e63d7..e8f44ba 100644
--- a/builtin-http-fetch.c
+++ b/http-fetch.c
@@ -1,8 +1,9 @@
#include "cache.h"
#include "walker.h"
-int cmd_http_fetch(int argc, const char **argv, const char *prefix)
+int main(int argc, const char **argv)
{
+ const char *prefix;
struct walker *walker;
int commits_on_stdin = 0;
int commits;
@@ -18,6 +19,8 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix)
int get_verbosely = 0;
int get_recover = 0;
+ prefix = setup_git_directory();
+
git_config(git_default_config, NULL);
while (arg < argc && argv[arg][0] == '-') {
Przeanalizujmy tę łatkę linia po linii.
-
Pierwsza linia
diff --git a/builtin-http-fetch.c b/http-fetch.c
jest nagłówkiem" git diff " w formiediff --git a/file1 b/file2
. Nazwy plikówa/
ib/
są takie same, chyba że w grę wchodzi zmiana nazwy/kopia (jak w naszym przypadku).--git
oznacza, że diff jest w formacie" git". -
Następne to jeden lub więcej rozszerzonych nagłówków linie. Pierwsze trzy
similarity index 95% rename from builtin-http-fetch.c rename to http-fetch.c
powiedz nam, że plik został przemianowany zbuiltin-http-fetch.c
nahttp-fetch.c
i że te dwa pliki są w 95% identyczne (co zostało użyte do wykrycia tej zmiany nazwy).
ostatnia linijka w rozszerzonym nagłówku diff, która jestindex f3e63d7..e8f44ba 100644
mówi nam o trybie danego pliku (100644
oznacza, że jest to zwykły plik, a nie np. dowiązanie symboliczne, i że nie ma on bitów uprawnień wykonywalnych), oraz o skróconym hashu preimage (Wersja pliku przed daną zmianą) i postimage (Wersja pliku przed daną zmianą). plik po zmianie). Ta linia jest używana przezgit am --3way
do próby połączenia trójdrożnego, jeśli patch nie może zostać zastosowany.
-
Następny jest dwuliniowy zunifikowany nagłówek diff
--- a/builtin-http-fetch.c +++ b/http-fetch.c
w porównaniu do wynikudiff -U
nie posiada on nazw od-Pliku-modification-time ani do-pliku-modification-time po źródłowych (preimage) i docelowych (postimage) plikach. Jeśli plik został utworzony, źródłem jest/dev/null
; jeśli plik został usunięty, docelowym jest/dev/null
.
Jeśli ustawisz zmienną konfiguracyjnądiff.mnemonicPrefix
na true, w miejsce przedrostkówa/
ib/
w tym dwuliniowym nagłówku można zamiastc/
,i/
,w/
io/
jako prefiksy, odpowiednio do tego, co porównujesz; zobacz git-config (1) -
Następnie pojawia się jeden lub więcej fragmentów różnic; każdy fragment pokazuje jeden obszar, w którym Pliki się różnią. Unified format hunks zaczyna się od linii
@@ -1,8 +1,9 @@
lub@@ -18,6 +19,8 @@ int cmd_http_fetch(int argc, const char **argv, ...
jest w formacie@@ from-file-range to-file-range @@ [header]
. Zakres from-file - range ma postać-<start line>,<number of lines>
, a to-file-range to+<start line>,<number of lines>
. Zarówno start-line, jak i liczba linii odnosi się do pozycji i długości kawałka odpowiednio w preimage i postimage. Jeśli liczba linii nie jest pokazana, oznacza to, że jest równa 0.Opcjonalny nagłówek pokazuje funkcję C, w której następuje każda zmiana, jeśli jest to plik C (jak opcja
-p
W GNU diff), lub odpowiednik, jeśli istnieje, dla innych typów plików. -
Następnie pojawia się opis różnic w plikach. Linie wspólne dla obu plików rozpoczynają się znakiem spacji. Linie, które faktycznie różnią się pomiędzy dwoma plikami znajduje się jeden z następujących znaków wskaźnikowych w lewej kolumnie drukowania:
- '+ ' -- wiersz został dodany tutaj do pierwszego pliku.
- ' - '-- linia zostaĹ ' a usuniÄ ™ ta z pierwszego pliku.
Tak więc, na przykład, pierwszy kawałek#include "cache.h" #include "walker.h" -int cmd_http_fetch(int argc, const char **argv, const char *prefix) +int main(int argc, const char **argv) { + const char *prefix; struct walker *walker; int commits_on_stdin = 0; int commits;
Oznacza, że
cmd_http_fetch
został zastąpiony przezmain
, a wierszconst char *prefix;
został dodany.Innymi słowy, przed zmianą, odpowiedni fragment then ' builtin-http-fetch.C ' File looked tak:
#include "cache.h" #include "walker.h" int cmd_http_fetch(int argc, const char **argv, const char *prefix) { struct walker *walker; int commits_on_stdin = 0; int commits;
Po zmianie fragmentu now ' http-fetch.plik c wygląda tak:
#include "cache.h" #include "walker.h" int main(int argc, const char **argv) { const char *prefix; struct walker *walker; int commits_on_stdin = 0; int commits;
-
Może być
\ No newline at end of file
Linia obecna(nie jest w przykładzie diff).
Jak Donal Fellows powiedział najlepiej jest ćwiczyć czytanie różnic na rzeczywistych przykładach, gdzie wiesz, co zmieniłeś.
Referencje:
- git-diff (1) manpage , sekcja " generowanie łat z -p "
- (diff.info) szczegółowy Unified węzeł, "szczegółowy opis Unified Format".
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:23
@@ -1,2 +3,4 @@ część diff
Ta część zajęła mi trochę czasu, aby zrozumieć, więc stworzyłem minimalny przykład.
Format jest zasadniczo taki sam jak diff -u
unified diff.
Na przykład:
diff -u <(seq 16) <(seq 16 | grep -Ev '^(2|3|14|15)$')
Tutaj usunęliśmy linie 2, 3, 14 i 15. Wyjście:
@@ -1,6 +1,4 @@
1
-2
-3
4
5
6
@@ -11,6 +9,4 @@
11
12
13
-14
-15
16
@@ -1,6 +1,4 @@
oznacza:
-
-1,6
: ten kawałek odpowiada linii 1 do 6 pierwszego pliku:1 2 3 4 5 6
-
znaczy "stary", jak zwykle powołujemy się na to jakodiff -u old new
. -
+1,4
mówi, że ten kawałek odpowiada linii 1 do 4 drugiego pliku.+
oznacza "nowy".Mamy tylko 4 linie zamiast 6, ponieważ 2 linie zostały usunięte! Nowy przystojniak jest po prostu:
1 4 5 6
@@ -11,6 +9,4 @@
dla drugiego jest analogiczne:
-
W starym pliku mamy 6 linii, zaczynających się od linii 11 starego pliku:
11 12 13 14 15 16
-
W Nowym pliku mamy 4 linie, zaczynające się od linii 9 nowego pliku:
11 12 13 16
Zauważ, że linia
11
jest dziewiątą linią nowego pliku, ponieważ usunęliśmy już 2 linie z poprzedniego kawałka: 2 i 3.
Hunk header
W zależności od wersji i konfiguracji git, możesz również uzyskać linię kodu obok linii @@
, np. func1() {
w:
@@ -4,7 +4,6 @@ func1() {
Można to również uzyskać za pomocą flagi -p
zwykłej diff
.
Przykład: stary plik:
func1() {
1;
2;
3;
4;
5;
6;
7;
8;
9;
}
Jeśli usuniemy linia 6
, diff pokazuje:
@@ -4,7 +4,6 @@ func1() {
3;
4;
5;
- 6;
7;
8;
9;
Zauważ, że nie jest to prawidłowa linia dla func1
: pominęła linie 1
i 2
.
Ta niesamowita funkcja często mówi dokładnie, do której funkcji lub klasy należy każdy kawałek, co jest bardzo przydatne do interpretacji różnic.
Jak dokładnie działa algorytm wyboru nagłówka jest omówione w: skąd pochodzi fragment w nagłówku Git diff hunk?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:28
Oto prosty przykład.
diff --git a/file b/file
index 10ff2df..84d4fa2 100644
--- a/file
+++ b/file
@@ -1,5 +1,5 @@
line1
line2
-this line will be deleted
line4
line5
+this line is added
Oto Wyjaśnienie (zobacz szczegóły tutaj ).
-
--git
nie jest poleceniem, to znaczy, że jest to wersja git diff (nie unix) -
a/ b/
są katalogami, nie są prawdziwe. jest to po prostu wygoda, gdy mamy do czynienia z tym samym plikiem (w moim przypadku a/ jest w indeksie, a b/ w katalogu roboczym) -
10ff2df..84d4fa2
są identyfikatorami blob tych 2 plików -
100644
jest "bitami trybu", co wskazuje, że jest to zwykły plik (nie wykonywalny i nie dowiązanie symboliczne) -
--- a/file +++ b/file
znaki minus pokazują linie w wersji a/, ale brakujące w wersji b/ ; A znaki plus pokazują linie brakujące w a/, ale obecne w b/ (w moim przypadku --- oznacza usunięte linie, a +++ oznacza dodane linie w b / i to plik w katalogu roboczym) -
@@ -1,5 +1,5 @@
aby to zrozumieć, lepiej pracować z dużym plikiem; jeśli masz dwie zmiany w różnych miejscach, otrzymasz dwa wpisy typu@@ -1,5 +1,5 @@
; Załóżmy, że masz plik line1 ... line100 i usunięte line10 i dodać nowy line100-otrzymasz:
@@ -7,7 +7,6 @@ line6 line7 line8 line9 -this line10 to be deleted line11 line12 line13 @@ -98,3 +97,4 @@ line97 line98 line99 line100 +this is new line100
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-19 11:35:07
Domyślny format wyjściowy (który pochodzi z programu znanego jako diff
, jeśli chcesz znaleźć więcej informacji) jest znany jako "unified diff". Zawiera zasadniczo 4 różne rodzaje linii:
- linie kontekstowe, które rozpoczynają się pojedynczą spacją,
- linie wstawiania, które pokazują linię, która została wstawiona, które zaczynają się od
+
, - linie delecji, które zaczynają się od
-
i - linie metadanych opisujące rzeczy wyższego poziomu, takie jak ten plik chodzi o to, jakie opcje zostały użyte do wygenerowania różnic, czy plik zmienił swoje uprawnienia, itd.
Radzę poćwiczyć czytanie różnic pomiędzy dwoma wersjami pliku, w którym dokładnie wiesz, co zmieniłeś. W ten sposób rozpoznacie, co się dzieje, kiedy to zobaczycie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-27 14:33:23
Na moim Macu:
info diff
następnie wybierz: Output formats
-> Context
-> Unified format
-> Detailed Unified
:
Lub Online man diff na gnu podążając tą samą ścieżką do tej samej sekcji:
Plik: diff.info, węzeł: szczegółowy Unified, Next: Example Unified, Up: Unified Format
Szczegółowy opis jednolitego formatu ......................................
Unified output format rozpoczyna z dwuliniowym nagłówkiem, który wygląda tak:
--- FROM-FILE FROM-FILE-MODIFICATION-TIME +++ TO-FILE TO-FILE-MODIFICATION-TIME
Znacznik czasu wygląda jak `2002-02-21 23: 30: 39.942229878 -0800' aby wskazać data, godzina z ułamkiem sekund i strefy czasowej.
Możesz zmienić zawartość nagłówka z opcją '--label=LABEL'; zobacz * Note Alternate Names.::.
Dalej jeden lub więcej przystojniaków z różnice; Każdy kawałek pokazuje jeden obszar gdzie pliki różnią się. Unified format wygląda tak:
@@ FROM-FILE-RANGE TO-FILE-RANGE @@ LINE-FROM-EITHER-FILE LINE-FROM-EITHER-FILE...
Linie wspólne dla obu plików zacznij od znaku spacji. Na linie, które faktycznie różnią się między dwa pliki mają jeden z następujących znaki wskaźnika w lewym wydruku kolumna:
`+' Do pierwszego pliku została dodana linia.
`-' Linia została tutaj usunięta z pierwszego pliku.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-27 14:23:36
Nie jest jasne z twojego pytania, która część diffów jest myląca: faktycznie diff lub dodatkowe informacje nagłówka Git drukuje. Na wszelki wypadek, oto szybki przegląd nagłówka.
Pierwsza linijka to coś w stylu diff --git a/path/to/file b/path/to/file
- oczywiście po prostu mówi do jakiego pliku służy ta sekcja Diffa. Jeśli ustawisz zmienną Boolean config diff.mnemonic prefix
, a
i b
zostaną zmienione na bardziej opisowe litery, takie jak c
i w
(commit i praca drzewo).
Następnie są "mode lines" - linie dające OPIS wszelkich zmian, które nie wymagają zmiany zawartości pliku. Obejmuje to nowe / usunięte pliki, przemianowane / skopiowane pliki i zmiany uprawnień.
W końcu jest taka linijka index 789bd4..0afb621 100644
. Prawdopodobnie nigdy cię to nie obchodzi, ale te 6-cyfrowe liczby szesnastkowe są skrótem SHA1 starych i nowych obiektów blob dla tego pliku(obiekt blob jest obiektem git przechowującym surowe dane, takie jak zawartość pliku). I oczywiście, {[7] } jest trybem pliku - trzy ostatnie cyfry to oczywiście uprawnienia; pierwsze trzy dają dodatkowe informacje o metadanych pliku (więc Post opisujący to ).
Następnie przechodzimy do standardowego unified diff output(podobnie jak klasyczne diff -U
). Jest podzielony na kawałki - kawałek jest sekcją pliku zawierającą zmiany i ich kontekst. Każdy plik jest poprzedzony parą linii ---
i +++
oznaczających dany plik, wtedy rzeczywisty diff to (domyślnie) trzy linie kontekstu po obu stronach linii -
i +
pokazujące usunięte / dodane linie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:15
W kontroli wersji różnice między dwiema wersjami są przedstawione w tzw. " różnicy "(lub synonimicznie"poprawki"). Przyjrzyjmy się dokładnie takiemu rozróżnieniu - i nauczmy się go czytać.
Spójrz na wyjście Diffa. Na podstawie tego wyjścia zrozumiemy wyjście git diff.
Porównywane pliki a / b
Nasz diff porównuje ze sobą dwa elementy: element A i element B. w większości przypadków A i B będą tym samym plikiem, ale w różne wersje. Chociaż nie jest używany bardzo często, diff może również porównać dwa całkowicie niepowiązane ze sobą pliki, aby pokazać, jak się różnią. Aby wyjaśnić, co jest właściwie porównywane, wyjście diff zawsze zaczyna się od zadeklarowania, które pliki są reprezentowane przez "A "i"B".
Metadane Pliku
Pokazane tutaj metadane pliku to bardzo techniczna informacja, której prawdopodobnie nigdy nie będziesz potrzebował w praktyce. Pierwsze dwie liczby reprezentują hashe (lub mówiąc prościej: "IDs") z nasze dwa pliki: Git zapisuje każdą wersję nie tylko projektu, ale także KAŻDEGO pliku jako obiekt. Taki hash identyfikuje obiekt pliku przy określonej rewizji. Ostatnia liczba jest wewnętrznym identyfikatorem trybu pliku (100644 jest tylko "zwykłym plikiem", podczas gdy 100755 Określa plik wykonywalny, a 120000 reprezentuje dowiązanie symboliczne).
Markery dla a / b
Dalej na wyjściu, rzeczywiste zmiany będą oznaczone jako pochodzące z A lub B. aby je odróżnić, A i B każdy ma przypisany symbol: dla wersji A jest to znak minus ( " - " ), a dla wersji B znak plus ("+") jest używany.
Chunk
Różnica nie pokazuje całego pliku Od początku do końca: nie chcesz widzieć wszystkiego w pliku 10 000 linii, gdy tylko 2 linie się zmieniły. Zamiast tego pokazuje tylko te części, które zostały faktycznie zmodyfikowane. Taka część nazywa się" kawałkiem "(lub"kawałkiem"). Oprócz faktycznie zmienionych linii, fragment zawiera również trochę "context": kilka (niezmienionych) linii przed i po modyfikacji, abyś mógł lepiej zrozumieć, w jakim kontekście zaszła ta zmiana.
Chunk Header
Każdy z tych kawałków jest poprzedzony nagłówkiem. Zamknięty w dwóch znakach " @ " każdy, Git informuje, które linie zostały dotknięte. W naszym przypadku następujące linie są reprezentowane w pierwszym fragmencie:
Z pliku A (reprezentowanego przez" -") wydobywa się 6 linii zaczynających się od linii nr. 34
Z pliku B (reprezentowanego przez"+") wyświetlane jest 8 linii, również zaczynających się od linii nr. 34
Tekst po zamykającej parze "@ @ " ma na celu wyjaśnienie kontekstu, ponownie: Git próbuje wyświetlić nazwę metody lub inne informacje kontekstowe o tym, skąd ten fragment został pobrany w pliku. Jednak w dużym stopniu zależy to od języka programowania i nie działa we wszystkich scenariuszach.
Zmiany
Każda zmieniona linia jest poprzedzona z symbolem " + "lub" -". Jak wyjaśniono, symbole te pomagają zrozumieć, jak dokładnie wyglądają wersje A i B: linia poprzedzona znakiem " - "pochodzi z A, podczas gdy linia ze znakiem" + " pochodzi z B. W większości przypadków, Git wybiera A i B w taki sposób, że możesz myśleć o a/ - jako o "starej" zawartości, a B / + jako o "nowej" zawartości.
Spójrzmy na nasz przykład:
Zmiana # 1 zawiera dwie linie poprzedzone znakiem"+". Ponieważ dla tych linii nie istniał żaden odpowiednik w A (nie linie z" -"), Oznacza to, że linie te zostały dodane.
Zmiana # 2 jest dokładnie odwrotna: W A Mamy dwie linie oznaczone znakami" -". Jednak B nie ma odpowiednika (nie ma linii"+"), co oznacza, że zostały usunięte.
W zmianie # 3, w końcu niektóre linie zostały zmodyfikowane: dwie linie " - "zostały zmienione, aby wyglądały jak dwie linie" + " poniżej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-19 13:12:21