簡體   English   中英

為什么在Git日志中看不到任何輸出,但在Git Diff中卻看到了?

[英]Why Do I See No Output With Git Log But I Do See This With Git Diff?

球隊,

我輸入: git log branchA..branchB -- /dir1/dir2

鍵入此“ git log”命令時,不會輸出任何內容。 但是,當我鍵入此“ git diff”命令時,將輸出許多文件。

git diff branchA..branchB -- /dir1/dir2

有誰知道為什么會有這種極端的差異? 我已經閱讀了文檔,但是不幸的是,這並沒有給我明顯的答案,我不得不冒險進入Internet的公海。

似乎如果使用“ git diff”命令輸出,則意味着文件在分支(branchA和branchB)之間進行了更改。 如果“ git diff”命令證明這些分支之間有變化,則“ git log”命令中應該有任何東西。

為什么“ git log”命令不返回任何內容,但是“ git diff”命令卻返回許多文件輸出和代碼更改?

TL; DR

首先,使用git rev-list來檢查branchA..branchB范圍內是否有任何提交(如果不想看到原始哈希ID,請添加--count )。 然后,如果提交,考慮增加--full-history ,也許-mgit log命令。

這里有很多要解壓的東西。 (如果您指向一個特定的存儲庫以及該特定存儲庫中的兩個特定分支名稱 ,則可能會少很多。)

首先, git loggit diff是完全不同的野獸。 但是值得注意的是, git log可以或多或少地運行 git diff git diff無法運行git log 但是, git diff可以完成git log無法完成的工作。 其次,雙點符號具有多種不同的含義 git log含義與git diff含義非常不同。 從某種意義上說,它對git diff毫無意義,因為您可以隨時替換:

git diff X..Y

有:

git diff X Y

也就是說,這里的兩個點僅用於將XY分開,您也可以通過將它們作為單獨的參數來進行操作。 不過,對於git log 不是這樣。 這使得git diff簡單,所以讓我們從git diff開始。

兩次提交

您已經跑步(無論如何有效):

git diff branchA branchB -- /file1/file2

這種形式的git diff ,給定兩個提交說明符和一個路徑, 1的作用是檢出兩個特定的提交中的每一個並進行比較。 沒有路徑限制器,您將獲得關於什么操作集將第一次提交更改為第二次提交的完整說明:添加文件A和B,刪除文件C和D,修改文件E到H,等等。使用路徑說明符/file1/file2 2從輸出中消除任何影響名稱不以該字符串開頭(或等於)的文件的指令。 (這里的斜杠只是相對於存儲庫的頂層。)


1一些Git命令采用pathspec參數。 git loggit diff命令沒有。 如果您不使用復雜的東西,則無需擔心。 如果您開始使用:/::(glob)以及其他棘手的pathspec選項,請注意它們在此處不可用。

2請注意,您的操作系統可能需要該file1/file2名或者一個文件名為file2的目錄/文件夾中的file1 ,或命名的目錄/文件夾的file2一個名為內file1 對Git來說,這些只是字符串-不涉及“文件夾性質”。 不過,最好在這里說/dir1/dir2


使用git log

關於git log有很多知識; 讓我們從兩點符號開始。 在這種情況下,您的兩個項目是branchAbranchB Git將(至少使用git log以及其他許多命令但不使用 git diff首先將其視為選擇branchB尖端可訪問的所有提交,減去從branchA尖端可訪問的所有提交 這使用了短語reachable from ,它值得一整個網絡教程: Think Like(a)Git (去讀吧!)

正如knittl在評論中指出的那樣 ,即使兩個名稱指定不同的提交,此列表也可以為空。 在這種情況下,正如我們將看到的, git log將不打印任何內容。 要查找哈希ID列表(不見其他內容),請使用git rev-list

git rev-list branchA..branchB

rev-list命令是許多Git命令使用的主要Git工作馬具,可以通過運行它或將其內置到其中來實現。 例如,所有cherry-pickrevertrebaselogshortlogpush內部使用git rev-list git fetch也使用它,但是在另一個 Git上而不是在您的Git上運行rev-list命令。

無論如何, git log現在實際上具有要步行的提交列表。 列表中有多少個提交一點也不明顯。 如果列表中只有一個提交,那么您的git loggit diff將做同樣的事情-產生相同的輸出-因此我們可以安全地假定列表中沒有提交,或者其中至少有兩個提交。 如果為空,但是提交不同,則說明了您的輸出。

如果不是這樣,情況會變得更加復雜,但是提交列表中可能至少包含一個合並提交 如果我們假設它確實有至少一個合並,那也可以為我們提供解釋。 Git現在要做的是按照一定的順序遍歷提交列表, 如果您沒有添加-- /file1/file2它現在可以做一些簡單的解釋:

  • 找到要執行的提交(在內部,這些實際上不在優先級隊列中,作為此構建列表和同時執行的一部分)。

    • 找到它的父母。 如果此提交是合並,請找到所有父母。 這實際上是rev-list操作的一部分: git loggit rev-list是從單一來源構建的,並共享它們的大部分代碼,而rev-list和log都使用此共享的walking代碼遍歷提交圖。
    • 根據所選的--pretty格式,打印來自提交的日志消息,以及任何主要的內容,例如提交哈希。
    • 如果提交不是合並,則在(單個)父級和提交本身之間運行git diff ,並顯示該輸出。 如果提交合並,則不顯示任何內容。
    • 將父項放到要提交的提交隊列中,然后返回頂部。

因此,您將通過枚舉“從branchB可以到達的提交減去從branchA可以到達的提交”,在git log / git rev-list找到git rev-list看到每個非合並提交的git diff

現在,您認為添加-- /file1/file2會影響這些差異,因此您只能看到那些已更改的文件……這是事實。 但這還不止於此:它啟用了“ 歷史簡化”

啟用“歷史記錄簡化”功能后, git log (和git rev-list )有意切斷了可達性圖的一部分。 特別是,在任何合並中 ,Git都會對文檔稱為TREESAME進行詳盡的計算。 這種計算等於將每次提交分解為僅在命令行上指定的文件和/或目錄列表中的那些文件,並比較每個此類文件的內容。

當合並的一個“分支”在所有文件上都為TREESAME時,在剝離其他文件之后,另一個不是TREESAME時,Git 丟棄not-TREESAME分支 ,包括通過合並的那個分支可到達的所有提交。 如果合並是章魚合並,並且至少一個父級具有TREESAME剝離后屬性,則Git或多或少隨機地選擇一個,然后跟隨那個,丟棄所有其他分支。 (如果所有腿都不同,則Git跟隨所有腿。)

然后,由於合並提交合並提交,因此默認情況下git log輸出任何內容 即使git log並未為此跳過差異列表, 3它可能也只是選擇了一些TREESAME父對象,因此差異列表仍然是空的。 這就是TREESAME的含義:剝離所有您選擇的文件后,其余的從合並提交到其選定的父級中都是相同的。

選擇了TREESAME父對象后,Git繼續走這條路。 如果branchA標識了被丟棄的分支中的某個提交,那么您可以(我認為)現在可以理解為什么此git log的輸出可能為空:從此處回到branchA任何位置,任何提交中的選定文件都可能沒有任何更改通過從branchB的尖端可以到達的提交重新加入。

如果實際上是歷史簡化已放棄了有趣的提交,則在git log命令中添加--full-history將向您顯示您想要查看的提交。 當然,您要查找的任何更改都有可能是由“ evil merge”引入的,因此您可能還需要-m選項,該選項強制git log顯示合並提交及其每個父項之間的完全區別。


3您可以告訴git log在合並時使用-c ,-- --cc-m來打印差異列表,每一個都有不同的效果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM