Как мне различать один и тот же файл между двумя разными коммитами в одной ветке?

Как в Git сравнить один и тот же файл между двумя разными коммитами (не смежными) в одной и той же ветке (например, master)?

Я ищу функцию сравнения, подобную той, которая содержится в Visual SourceSafe (VSS) или Team Foundation Server (TFS).
Возможно ли это в Git?


person systempuntoout    schedule 26.07.2010    source источник
comment
Если вам нужно сделать это в GitHub - проверьте это   -  person Pankaj Singhal    schedule 06.10.2020


Ответы (11)


Из git-diff справочная страница:

git diff [--options] <commit> <commit> [--] [<path>...]

Например, чтобы увидеть разницу для файла «main.c» между текущим моментом и двумя обратными фиксациями, вот три эквивалентные команды:

$ git diff HEAD^^ HEAD main.c
$ git diff HEAD^^..HEAD -- main.c
$ git diff HEAD~2 HEAD -- main.c
person mipadi    schedule 26.07.2010
comment
.. на самом деле не нужен, хотя он будет работать с ним (за исключением, возможно, довольно старых версий). Вы также можете использовать git log или gitk, чтобы найти SHA1, которые нужно использовать, если два коммита находятся очень далеко друг от друга. gitk также имеет выделенное различие - ›это и различие этого -› выбранное в его контекстном меню. - person Cascabel; 26.07.2010
comment
Будет ли это работать, даже если имя файла было изменено между двумя коммитами? - person reubenjohn; 14.02.2014
comment
Итак, какова цель - - person user64141; 06.08.2014
comment
@ user64141 -- полезен, например когда у вас есть файл с именем -p. Хорошо использовать в скриптах, только в редких случаях, когда это необходимо на практике. - person Palec; 30.12.2014
comment
Примечание: вам нужно использовать пути относительно корня репо. Пути относительно текущего рабочего каталога работать не будут. - person Kevin Wheeler; 30.06.2015
comment
git diff master..HEAD -- $(find your_search_folder/ -name '*.c') для сравнения всех .c файлов внутри каталога. - person Andrei-Niculae Petre; 20.12.2015
comment
Синтаксис HEAD^^^ означает сравнение с 3 фиксациями репо назад, а не с 3 фиксациями файлов назад. Обойти это можно, указав дату, например. git diff -w @{2016-01-01} filename -w означает игнорировать изменения пробелов. - person Andrew Murphy; 18.06.2016
comment
Предположим, мы работаем с одной веткой: предположим, вы сделали фиксацию, а затем изменили file.c. Как бы вы сравнили текущее состояние файла с состоянием того же файла в предыдущем коммите? (Я спрашиваю, потому что аргументы команды ожидают <commit> <commit>, а не <current changes yet to be committed> <commit>) - person Minh Tran; 01.12.2017
comment
К @KevinWheeler - я на самом деле вижу противоположное как в ubuntu, так и в windows git. Путь должен быть относительно текущего каталога, а не корня хранилища. Вы все еще наблюдаете такое же поведение? - person aggieNick02; 11.01.2018
comment
У меня не работает. Всегда показывает ноль изменений, но в файле есть изменения. - person ; 02.03.2018
comment
Если между коммитами произошло изменение структуры папок, вам нужно использовать git diff commit_hash_1: folder / file.ext commit_hash_2: new_folder / file.ext - person Jerin; 07.12.2018
comment
На указанной странице руководства не упоминается HEAD~2 или даже ~. Кроме того, почему diff HEAD~2 HEAD~1 или diff HEAD~3 HEAD~2 и т. Д. Ничего не возвращают ?? - person Marc; 03.04.2019
comment
Пути являются относительными: команда git diff A B c из папки /git-clone/a/b даст тот же результат, что и git diff A B a/b/c из папки /git-clone - person Oliver; 25.01.2021

Вы также можете сравнить два разных файла в двух разных версиях, например:

git diff <revision_1>:<file_1> <revision_2>:<file_2>

person Jakub Narębski    schedule 27.07.2010
comment
обратите внимание, что похоже, что если <file_1> и <file_2> находятся в текущем каталоге, а не в управляемом каталоге git верхнего уровня, нужно добавить ./ в Unix: <revision_1>:./filename_1 - person Andre Holzner; 12.08.2013
comment
‹Revision›: можно опустить, чтобы вы могли сравнить файл, который еще не был зафиксирован. - person Yaroslav Nikitenko; 06.12.2015
comment
Обратите внимание, что в Windows нужно использовать '/' для путей к файлам, а не '\'. - person np8; 23.10.2018
comment
Есть ли способ выполнить это различие так, чтобы один из двух файлов был локальным? Т.е. когда ваш difftool открыт, файл не является копией во временном каталоге. В том же духе, что и разница между git diff HEAD..HEAD~1 и git diff HEAD~1 - person Gregory Kuhn; 11.03.2021

Если вы настроили "difftool", вы можете использовать

git difftool revision_1:file_1 revision_2:file_2

Пример: сравнение файла из его последней фиксации с предыдущей фиксацией в той же ветке: при условии, что если вы находитесь в корневой папке проекта

$git difftool HEAD:src/main/java/com.xyz.test/MyApp.java HEAD^:src/main/java/com.xyz.test/MyApp.java

У вас должны быть следующие записи в вашем ~ / .gitconfig или в файле project / .git / config. Установите p4merge [это мой любимый инструмент сравнения и слияния]

[merge]
    tool = p4merge
    keepBackup = false
[diff]
    tool = p4merge
    keepBackup = false
[difftool "p4merge"]
    path = C:/Program Files (x86)/Perforce/p4merge.exe
[mergetool]
    keepBackup = false
[difftool]
    keepBackup = false
[mergetool "p4merge"]
    path = C:/Program Files (x86)/Perforce/p4merge.exe
    cmd = p4merge.exe \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"
person Anver Sadhat    schedule 03.01.2012

Проверьте $ git log, скопируйте SHA-1 ID двух разных коммитов и запустите git diff команда с этими идентификаторами. Например:

$ git diff (sha-id-one) (sha-id-two)
person Vibhuti    schedule 19.04.2012
comment
Если вам нужна разница для определенного файла, добавьте путь к нему в конце команды. - person hBrent; 14.07.2015
comment
Также выполните git pull, чтобы загрузить полную информацию о дереве, если две фиксации находятся в разных ветвях. В противном случае вы получите фатальную ошибку: плохой объект. - person user238607; 01.12.2018
comment
git diff (sha-id-one) (sha-id-two) -- filename.ext без имени файла он перечислит различия всех файлов в этих двух фиксациях. - person SherylHohman; 18.01.2019

Если вы хотите видеть все изменения в файле между двумя коммитами по отдельности, вы также можете сделать

git log -u $start_commit..$end_commit -- path/to/file

person cxreg    schedule 26.07.2010
comment
Что такое $ start_commit и $ end_commit? Являются ли они буквальными, а если нет, можете ли вы привести пример? - person Peter Mortensen; 24.01.2018
comment
Это переменные оболочки, которые содержат начальную и конечную ревизии, которые вместо этого могут быть литералами sha1 или refs - person cxreg; 25.01.2018

Вот сценарий Perl, который выводит команды Git diff для заданного файла, найденные в команде журнала Git.

E.g.

git log pom.xml | perl gldiff.pl 3 pom.xml

Урожайность:

git diff 5cc287:pom.xml e8e420:pom.xml
git diff 3aa914:pom.xml 7476e1:pom.xml
git diff 422bfd:pom.xml f92ad8:pom.xml

которые затем можно было вырезать и вставить в сеанс окна оболочки или передать по конвейеру /bin/sh.

Примечания:

  1. число (в данном случае 3) указывает, сколько строк нужно напечатать
  2. файл (в данном случае pom.xml) должен быть согласован в обоих местах (вы можете обернуть его в функцию оболочки, чтобы предоставить один и тот же файл в обоих местах) или поместить его в двоичный каталог как сценарий оболочки

Код:

# gldiff.pl
use strict;

my $max  = shift;
my $file = shift;

die "not a number" unless $max =~ m/\d+/;
die "not a file"   unless -f $file;

my $count;
my @lines;

while (<>) {
    chomp;
    next unless s/^commit\s+(.*)//;
    my $commit = $1;
    push @lines, sprintf "%s:%s", substr($commit,0,6),$file;
    if (@lines == 2) {
        printf "git diff %s %s\n", @lines;
        @lines = ();
    }
    last if ++$count >= $max *2;
}
person user2520657    schedule 11.07.2013

Если вы хотите сделать разницу с более чем одним файлом, с помощью метода, указанного @mipadi:

Например. diff между HEAD и вашим master, чтобы найти все .coffee файлы:

git diff master..HEAD -- `find your_search_folder/ -name '*.coffee'`

Это будет рекурсивно искать в вашем your_search_folder/ все .coffee файлы и различать их и их master версии.

person Andrei-Niculae Petre    schedule 30.11.2012

Если у вас есть несколько файлов или каталогов и вы хотите сравнить непостоянные коммиты, вы можете сделать это:

Создайте временную ветку (в этом примере "ревизия")

git checkout -b revision

Вернуться к первой цели фиксации

git reset --hard <commit_target>

Черри выбирает тех, кто совершает интерес

git cherry-pick <commit_interested> ...

Применить разницу

git diff <commit-target>^

Когда ты закончишь

git branch -D revision
person dvdvck    schedule 25.08.2012
comment
Спасибо за это решение. Это хорошо сработало для моего варианта использования. Единственное, что я хотел бы обновить, это то, что, когда вы закончите, вы не сможете удалить ветку, пока не отключите ее. - person Steven Dix; 09.07.2013

Еще один способ использовать великолепие Git ...

git difftool HEAD HEAD@{N} /PATH/FILE.ext
person Edward J Beckett    schedule 02.08.2012
comment
Я определил псевдоним из этого ответа, который работает с bash: difftool-file = "!git difftool HEAD@{\"$2\"} HEAD \"$1\" #" - person blueogive; 14.05.2017

Если вам нужно простое визуальное сравнение в Windows, например, вы можете получить его в Visual SourceSafe или Team Foundation Server (TFS), попробуйте следующее:

  • щелкните правой кнопкой мыши файл в проводнике
  • выберите "История Git"

Примечание. После обновления до Windows 10 я потерял параметры контекстного меню Git. Однако вы можете добиться того же, используя "gitk" или "gitk filename" в командном окне.

Как только вы вызовете Git History, запустится инструмент Git GUI с историей файла в верхней левой панели. Выберите одну из версий, которую хотите сравнить. Затем щелкните правой кнопкой мыши вторую версию и выберите либо

Отличить это -> выбрано

or

Выбрано различие -> это

Различия с цветовой кодировкой появятся в нижней левой панели.

person Resource    schedule 08.01.2015
comment
Примечание для тех, кто проголосовал против: это простое решение, легко реализуемое и решающее проблему OP. Он работает в Windows, которую OP явно использует (см. Ссылки на TFS и VSS в вопросе). - person Resource; 04.01.2019

Все остальные ответы более полные, так что проголосуйте за них. Это просто для того, чтобы помнить, что вы можете не знать идентификатор недавнего коммита. Обычно я устанавливаю себя в ветке, которую хочу сравнить, и запускаю инструменты сравнения, зная старый uid фиксации (вы можете использовать другие обозначения):

git checkout master
git difftool 6f8bba my/file/relative/path.py

Также проверьте этот другой ответ здесь, чтобы установить инструмент, который вы хотите открыть в git для сравнения файла: Настройка diff инструмент с .gitconfig И чтобы узнать больше о difftool, перейдите к документу difftool

person Raúl Martín    schedule 11.08.2020