Странный вывод «git diff», «git diff HEAD» и «git diff --staged»? - PullRequest
3 голосов
/ 27 мая 2020

Существует 3 основных git diff версии:

  • git diff - разница между РАБОЧИЙ КАТАЛОГ и ЭТАП
  • git diff --staged - разница между HEAD и STAGE
  • git diff HEAD - разница между ГОЛОВА и РАБОЧИЙ КАТАЛОГ

Выше приведены определения, которые я нашел почти повсюду от разных людей по net

Я выполнил некоторые коммиты для 3 файлов в следующем порядке:

ce6f5bb (HEAD -> master) 6th commit, file1
c1c67da 5th commit, file3    
ea51776 4th commit, file1 file2    
001675b 3rd commit, file1 file2    
ec04f53 2nd commit, file2    
21cb6c1 1st commit, file1  

a. file2 изменено в рабочем каталоге
b. Ничего НЕ ЭТАПНО для фиксации
c. file1 & file3 без изменений


Мои запросы:

1. git diff

    git diff
    diff --git a/file2.txt b/file2.txt
    index 21106bf..c755a1e 100644
    --- a/file2.txt
    +++ b/file2.txt
    @@ -1,3 +1,4 @@
     123
     345
     678
    +90.    

Даже при том, что STAGING AREA БЫЛА ПУСТО, почему был показан diff?


2. git diff HEAD

    git diff
    diff --git a/file2.txt b/file2.txt
    index 21106bf..c755a1e 100644
    --- a/file2.txt
    +++ b/file2.txt
    @@ -1,3 +1,4 @@
     123
     345
     678
    +90.    

если LAST COMMIT (HEAD) был связан с file1, то почему отображается diff файла2?
HEAD вообще не содержит ничего, связанного с file2



СЕЙЧАС ПОСЛЕ STAGING file2 :

3. git diff

Он ничего не показывает!
(я предполагаю, что он будет показывать разницу только в том случае, если файл является промежуточным а также некоторые изменения , кроме поэтапной версии, сделаны и в рабочем каталоге)
Ну, если это так, то почему diff был показан в 1.


4. git diff --staged

    git diff
    diff --git a/file2.txt b/file2.txt
    index 21106bf..c755a1e 100644
    --- a/file2.txt
    +++ b/file2.txt
    @@ -1,3 +1,4 @@
     123
     345
     678
    +90.    

снова, если HEAD указывает на file1, тогда почему отображается diff файла2?



Я СОЗДАЛ ЭТО ИЗОБРАЖЕНИЕ НИЖЕ (Примечание: ДРУГОЙ СЦЕНАРИЙ. Не такой, как указано выше) :

для git diff HEAD, я предполагаю, что для каждого ОТСЛЕЖИВАЕМОГО ФАЙЛА HEAD будет продолжать движение в обратном направлении, пока не найдет ПОСЛЕДНЮЮ ВЕРСИЮ ЭТОГО ФАЙЛА, которая была зафиксирована, для сравнения с версией в рабочем каталоге

Если мы рассмотрим новый сценарий, как показано ниже, тогда для git diff HEAD, это похоже на то, что я предположил?

enter image description here

1 Ответ

2 голосов
/ 28 мая 2020

Вы делаете одну фундаментальную ошибку, а затем распространяете эту ошибку на каждую из своих различных команд.

Ошибка в том, что вы думаете о фиксации как изменении . Коммит - это не набор изменений. Коммит содержит снимок файлов. Более того, промежуточная область никогда не бывает пустой , 1 , она просто соответствует текущей фиксации , изначально.

Файлы file1.txt, file2.txt и file3.txt существуют в:

  • вашем рабочем дереве в виде простых файлов;
  • индексной / промежуточной области, как файлы в специальном Git формат фиксации, готовый к фиксации; и
  • каждая фиксация.

Каждая копия каждого файла может соответствовать другой копии того же файла (или любого другого файла) или может отличаться .

Имя HEAD выбирает одну конкретную фиксацию. 2 В начале ваших различных тестов имя HEAD selected commit ce6f5bb. Таким образом, на данный момент вам доступны три файла с именами file1.txt и Git, помимо тех, что указаны в предыдущих коммитах:

  • ce6f5bb:file1.txt, иначе HEAD:file1.txt: эта копия file1.txt заморожен в фиксации и не может быть изменен.
  • :file1.txt: эта копия file1.txt находится в области индекса / промежуточной обработки. Вы можете заменить его новой копией в любое время.
  • file1.txt: это просто обычный файл. На самом деле это не в Git. Это обычный файл в вашем рабочем дереве.

Также есть три копии file2.txt и три копии file3.txt.

Выполняется git diff без arguments сравнивает все три файла в HEAD со всеми тремя файлами в вашем рабочем дереве. В выводе упоминаются только те, которые отличаются.

Running git diff --staged или git diff --cached сравнивает все три файла в HEAD со всеми тремя файлами в промежуточной области. В выводе упоминаются только те, которые отличаются.

Запуск git diff HEAD сравнивает все три файла в HEAD со всеми тремя файлами в вашем рабочем дереве. В выводе упоминаются только те, которые отличаются.

Обратите внимание, что когда вы используете git log -p или git show для просмотра фиксации, Git делает git diff снимка родительской фиксации - ее файлов - против снимка этого коммита. Вы видите только те файлы, которые отличаются друг от друга. Так что выглядит как фиксация сохраняет изменения, но на самом деле он просто сохраняет снимок.

Обратите внимание, что git status запускает два git diff s: один сравнивает HEAD vs staging-area, т. е. делает git diff --staged и упоминает только имена файлов без отображения различий. Это изменения, подготовленные для файлов фиксации. Второй diff сравнивает индекс с рабочим деревом, т. Е. Делает git diff и упоминает только имена файлов. Это изменения, не поставленные для фиксации .


1 Промежуточная область может быть полностью пустой и находится в свободном sh репозиторий, в котором еще нет файлов и еще нет git add -ed. Вы также можете git rm каждый файл, в результате чего промежуточная область станет пустой. Но обычно он полон копий файлов из коммита HEAD, пока вы не используете git add для замены этих файлов на файлы из рабочего дерева.

2 Вы можете задайте Git два вопроса о специальном имени HEAD:

git rev-parse HEAD

спрашивает Git Что ha sh ID представляет HEAD, т.е. каков текущий коммит? Это тот, который спрашивает git diff. Или:

git symbolic-ref HEAD
git rev-parse --symbolic-full-name HEAD

спрашивает Git Какое имя ветки обозначает HEAD, т.е. какая ветка git status сообщит, что я нахожусь? Этот вопрос задает git commit, например, когда идет обновление имени ветки.

...