[英]Git log 2 tags and filter commits for a particular path
我有一個包含許多不同文件夾和標簽的存儲庫。 我想列出特定文件夾的 2 個發布標簽之間的提交。
我試過git log --oneline -- ${folder path} tag1 tag2
它似乎只過濾到指定文件夾路徑中的提交,但它似乎顯示的提交比標簽 1 和標簽 2 之間的差異更多。
有沒有辦法列出特定指定文件夾路徑的 2 個不同標簽之間的提交?
這里有很多問題:
--
選項之后的所有內容都被視為文件名。 (例如,這使您可以查找名為master
的文件。)因此,此處的tag1
和tag2
被視為文件名——它們不是指任何提交。 解決這個問題很容易,因為您只需將tag1
和/或tag2
移動到--
的另一側。
之間的整個概念很棘手,因為提交不一定都排在整齊的一排。 解決這個問題可能要困難得多:您必須確定之間的含義。
當您為git log
提供路徑名稱時,這將啟用它所謂的歷史簡化。 對於您的特定用途而言,這是否真的是一個問題也是一個難題,但如果它是一個問題,解決它實際上很容易:只需添加--full-history
以禁用歷史簡化。
所以你可能想要:
git log --oneline --full-history <something with the tags> -- <folder-name>
僅當結果中似乎缺少某些提交時才需要--full-history
。
something
首先,請記住,Git 中的每個提交都包含所有文件的完整快照,以及有關該快照的一些元數據:誰制作了它(作者姓名,email,以及日期和時間戳加上相同的committer),一條日志消息,以及——對我們來說最重要的——一些先前提交的原始 hash ID,Git 將其稱為此提交的父級或父級。
每個提交都有一個獨特的、又大又丑的 hash ID。 這實際上是提交的真實名稱。 所有其他名稱,無論是像master
這樣的分支名稱、像v2.1
這樣的標簽名稱,還是像HEAD~3
這樣的相對名稱,都只是讓 Git 找到原始 hash ID 的一種方式。 同時,每個名稱(包括分支名稱和標簽名稱)僅包含一個hash ID。 當一個 hash ID 是一個特定的提交時, 1就是由分支或標簽命名的提交。 我們說名稱指向提交。
但由於提交還包含提交 hash ID,因此提交也指向提交。 事實上,這正是 Git 存儲庫中歷史的發生方式。 一個名稱——通常是像master
這樣的分支名稱——通過持有其 hash ID 指向最后一次提交。 如果我們讓H
代表實際的 hash ID,我們可以這樣畫:
H <-- master
同時,提交H
包含其父提交的 hash ID。 我們稱其為G
,因此H
指向G
:
G <-H <-- master
當然G
有它自己的父級。 我們稱之為F
,它也有自己的父級,依此類推:
... <-F <-G <-H <-- master
這是一個很好的簡單線性提交鏈。 如果存儲庫中只有八個提交,都像這樣連續排列,我們可以將它們繪制為:
A--B--C--D--E--F--G--H <-- master
由於懶惰和缺乏角度方向的箭頭,我現在使用線條而不是箭頭來連接提交,但請記住它們實際上都是向后指向的箭頭。 我們可以使用內部箭頭將 go 從提交H
返回到A
,但不能從A
轉發到H
。
(提交A
很特殊:作為某人的第一個提交,它不能有父提交,所以它沒有。Git 將此稱為根提交。每個非空 Git 存儲庫都有至少一個根提交。這就是當我們回顧歷史時,我們可以停止追溯。)
要將新提交添加到某個分支,Git 只需用指向當前提交的箭頭寫出新提交,然后將新提交的實際 hash ID 寫入分支名稱。 例如,從:
...--G <-- master
至:
...--G--H <-- master
Git 剛剛用父 hash G
編寫了新的提交H
,然后將H
的實際 hash 寫入名稱master
。
但 Git 的歷史往往不是這樣的線性。 人們創建新的分支,然后在這些分支上進行新的提交,這會導致如下圖:
I--J <-- br1
/
...--G--H--L <-- master
\
K <-- br2
隨后有人可能會做git checkout master; git merge br1
git checkout master; git merge br1
以將分支 1 重新合並到master
中,這會產生:
I--J <-- br1
/ \
...--G--H--L---M <-- master
\
K <-- br2
新的合並提交M
指向L
(作為它的第一個父節點)和J
(作為它的第二個父節點)。
技巧問題:在哪個分支上提交
H
?答:實際上是在所有三個分支上。 Git 在這里很特別:許多版本控制系統保存提交是在哪個分支上進行的,而這就是提交所在的分支,永遠。 Git 不會將此信息保存在任何地方。 如果您可以從分支名稱指向的提交開始到達該提交,則該提交位於分支上。 因此,從
master
開始,我們可以在從L
的一跳中返回H
,或者在添加M
后從M
的兩跳中返回 H 。 從br1
開始,我們可以分兩跳回到H
:從J
開始,go 到I
,然后是H
。 從br2
我們 goK
然后H
。 所以H
在所有三個分支上。
1分支名稱被限制為僅包含提交 hash ID,因此分支名稱自動指向提交。 標簽名稱的限制較少:它們可以直接指向提交,在這種情況下,Git 稱它們為輕量級標簽。 或者,他們可以指向一個標簽 object ,它有自己唯一的 hash ID。 然后標記 object 指向另一個對象(通常是提交),因此標記仍然指向提交,但通過標記 object 間接指向。 這就是您可以使用額外信息(例如發行說明或 GPG 簽名)制作帶注釋的標簽的方法。
讓我們使用其中一種圖表並添加一些標簽名稱,它們像分支一樣指向特定的提交,但不一定位於分支的末尾。 (特別是,一旦你創建了一個標簽名稱,你應該讓它永遠指向同一個提交,通過它的 hash ID。)所以我們可能有:
tag:v0.7 tag:v0.8
| |
v v
...--G--H--I--M--N--O--P <-- branch1
\
J--K--L <-- branch2
^
|
tag:v0.9
哪些提交是“介於”標簽v0.7
和v0.8
之間? 我想大多數人都會同意它是IMN
,或者可能HIMNO
,或者類似的東西。
但是:哪些提交是“介於”標簽v0.7
和v0.9
之間? 哪些在v0.8
和v0.9
之間? 我想很多人會不同意。
如果事實證明提交M
實際上是一個合並,而不是常規提交,那么繪圖應該看起來像這樣:
tag:v0.7 tag:v0.8
| |
v v
...--G--H--I---M--N--O--P <-- branch1
\ /
J--K--L <-- branch2
^
|
tag:v0.9
現在哪些提交在各個標簽“之間”?
Git 給你的東西——Git 給你的所有東西——是使用各種修飾符來遍歷實際圖形的能力。 Git 通過從結尾開始(例如,在像P
這樣的提交處)並向后工作,在它可以實際工作的唯一方向上,使用連接提交的那些向后指向的箭頭來做到這一點。
您提供給git log
的任何分支或標簽名稱都算作以下之一:
例如,假設我們有第一張圖:
tag:v0.7 tag:v0.8
| |
v v
...--G--H--I--M--N--O--P <-- branch1
\
J--K--L <-- branch2
我們告訴 Git:從P
開始,但在L
停止。 顯然,從P
開始實際上不會讓我們提交L
,因為我們 go P
、 O
、 N
、 M
、 I
、 H
、 G
等等。 但是,通過告訴 Git在L
處停止,我們真正的意思是在從L
到達的任何提交處停止:所有L
、 K
、 J
、 G
等向后都是停止點。
我們可能用於從P
開始但在L
停止的語法是:
branch2..branch1
這意味着從branch1
的尖端(即P
)可到達的所有提交,不包括從branch2
的尖端(即L
)可到達的所有提交。
相同的語法適用於標簽名稱。 實際上,它的工作方式完全相同:僅提及標簽名稱,如git log v0.8
中,意味着將此標簽指向的提交視為起點。 提到兩個標簽名稱,它們之間有兩個點,意味着將此標簽指向的提交視為停止點。 所以:
v0.7..v0.8
將從O
開始並在H
停止。 這將排除提交H
,即它只會查看提交O
,然后是N
,然后是M
,然后是I
。
如果名稱v0.9
指向提交K
, v0.9..v0.8
將查看以O
開頭的提交並向后工作,直到它停止在G
。 0.9
在0.8
之后並不重要。 Git 根本沒有使用這些數字。 Git 專門使用圖表來包含或排除各種提交。
當圖表中有合並時,事情就會變得棘手。 在這里,您有時可能需要一個額外的標志--ancestry-path
。 但就像--full-history
一樣,這開始變得有點復雜,所以我們可能應該到此為止。
不過,我忍不住要提到第三種選擇,因為有些人在說“介於”時會想要這個。 除了兩點語法stop..start
,還有一個三點語法。 這意味着可以從任一名稱訪問的所有提交,除了可從兩個名稱訪問的所有提交。 也就是說,給定:
...--G--H--I--M--N--O--P <-- branch1
\
J--K--L <-- branch2
語法branch1...branch2
表示提交HIMNOP
並提交JKL
(但不是按此順序,因為 Git 必須向后工作)。 排除的提交從G
開始並向后工作,因為G
在兩個分支上。
你的語法幾乎是正確的。
要列出一系列提交,請使用tag1..tag2
,並將所有提交放在--
之前。 因此,您的命令應如下所示:
git log --oneline tag1..tag2 -- path
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.