簡體   English   中英

Git 來自幾個(不是全部)未暫存文件的補丁

[英]Git patch from several (not all) unstaged files

我閱讀了有關git patch命令的信息,但所有示例都顯示了如何為所有未暫存或緩存的文件,甚至是某些提交包含的所有文件(從一個提交到另一個提交)獲取補丁。 但是假設我有10 個未暫存的文件,我需要為其中的 6 個創建一個適當的補丁 我怎樣才能做到這一點? 如果有辦法創建這樣的補丁,我該如何應用它?
很抱歉,如果很明顯。

您必須首先定義短語適當的補丁 什么使補丁正確? 是什么讓一個人不合適? 就此而言,補丁差異有什么區別? 沒有一個固定的答案,但請參閱補丁和差異文件之間的區別

也就是說, git diff產生差異,並且非常靈活。 它是供人類使用的,而不是供機器使用的,因此它的 output 可能是也可能不是您想要的(特別是因為您沒有定義任何術語)。 The git format-patch program is less flexible and meant more for use by machines: it produces output that can be digested easily by git apply , which is meant to apply a single patch without committing it, or git am , which is meant to apply一整套補丁以“郵箱格式”存儲在您的計算機上,提交每個補丁。 (這里am應用郵箱的縮寫,或多或少。)

因為你還沒有定義你的術語,所以你的問題沒有一個正確的答案。 如果我們假設您的意思是生成git apply可以應用的文件,我們會得到一個可能的答案。 如果我們假設您的意思是生成git am可以應用和提交的郵箱格式補丁,我們會得到不同的答案。

git format-patch命令將從一些提交或提交中生成一個郵箱格式的補丁(或一系列補丁)。 所以要使用它,你必須做出一個 commit 如果您願意,您可以簡單地在新分支上提交您希望在補丁中包含的那些特定文件。 (請參閱下面的詳細信息。)

The git diff program, or any of its more machine-oriented related commands ( git diff-tree , git diff-files , git diff-index ) will produce a human-readable diff. 如果沒有上色,則適合與git apply一起使用。 要使用這些,您無需提交。

正如LeGEC 所指出的,您可以在特定文件上使用git diff 請注意,默認情況下, git diff -- paths將每個指定路徑的索引副本與同一路徑的工作樹副本進行比較。 這可能就是你想要的。 如果您已將git diff配置為始終生成彩色 output,請在一個git diff操作期間將其關閉。 將 output 保存在某處:

git diff -- file1 ... fileN > /tmp/patch

或者:

git diff --color=never -- file1 ... fileN > /tmp/patch

如果您需要禁用着色。

長:關於提交

如果以上就夠了,就沒有必要再看這篇的rest了。

如果您對正確補丁的定義意味着git am可以變成一個提交,那么您將需要進行新的提交。 這就是了解stagednot staged以及分支名稱和提交如何工作變得非常重要的地方。

Git 的核心其實就是提交。 分支——或者更具體地說,分支名稱——很有用,特別是如果你是人類,但它們並不是 Git 的真正含義。 Git 都是關於提交的。

每個提交都有編號,但這些數字不是簡單的順序計數。 我們找不到提交#1,然后提交#2,依此類推。 相反,每個提交都會獲得一個唯一的hash ID 這個東西看起來是隨機的,但實際上完全是非隨機的,並且是經過仔細計算的,因此每個Git 都會以相同的方式編號 100% 相同的、逐位相同的提交。 這樣,每個地方的每個 Git 都會同意這個提交得到這個hash ID,並且沒有其他提交得到這個 hash ID。

提交的內容分為兩部分:數據元數據:

  • 提交中的數據非常簡單:它是 Git 知道的每個文件的完整快照。

    這顯然使 Git 存儲庫變得非常龐大,因為每個提交都存儲每個文件。 但他們不會(變得非常肥胖)。 原因是文件以特殊的、只讀的、僅限 Git 的、壓縮的和去重復的格式存儲。 如果您進行一千次提交,每個提交有 1000 個文件,但每次重用1000 個文件中的 999 個,那么所有一千次提交與其他提交共享999 個文件。

    (除此之外還有更多,但重復數據刪除是第一步,而且是非常大的一步。)

  • 提交中的元數據是有關提交的信息。 例如,這是 Git 存儲提交人的姓名和 email 地址的地方。 不過,在此元數據中,Git 存儲了 Git 自身需要的一組特定信息。 每個提交都存儲其父提交的提交編號——hash ID。 這就是歷史在存儲庫中的存在方式。

由於提交中的文件是只讀的——而且只有Git,永遠凍結,壓縮成這種特殊的凍干格式,只有 Git 本身可以使用——使用的文件必須從提交中提取. 這就是git checkout (或者,由於 Git 2.23, git switch )所做的。 您選擇一個提交並告訴 Git:從該提交中提取所有文件,以便我可以看到它們並使用 / 處理它們。

由於每個提交都會記住其先前的提交,因此您需要做的就是使用Git,讓 Git 記住最后一次提交的唯一 hash ID。 這是分支名稱的來源。分支名稱僅包含要被視為該分支一部分的最后一次提交的 hash ID。

這意味着我們可以像這樣繪制一個分支:

... <-F <-G <-H   <--master

名稱master持有最后一次提交的實際 hash ID,此時為 hash ID H 該提交包含您所有文件的快照,並且還包含先前提交G的 hash ID。

Git can look up any commit—any internal object, really—by its hash ID, so Git can look up commit H , extract all of its files, and let you work on it. 或者, Git 可以查找提交H ,找到其父 hash ID G ,並查找提交G Git 然后可以提取G的文件,或查找其父 hash ID F 這是 Git 的第一個大秘密。

提交、你的工作樹和索引

鑒於上述只讀提交和讀/寫文件,我們已經看到 Git 必須將提交提取到您可以查看和處理文件的區域中。 該區域是您的工作樹工作樹 因此,每個感興趣的文件都有兩個副本:一個在當前提交中,它一直被凍結,另一個在您的工作樹中,您可以使用它。 它非常簡單,有一個轉折點:您可以在 Git知道的區域創建文件。

不過,這里真正棘手的部分是 Git 如何進行新的提交,以及 Git確實知道哪些文件。 例如,您可能認為 Git 只會保留文件名列表,並使用您的工作樹文件進行新提交......但事實並非如此。

取而代之的是,Git 在中間位置保留了第三個副本——好吧,一個去重的副本,采用凍干格式。 在當前提交和您的工作樹之間,Git 具有Git 在結帳時從提交中取出的每個文件的另一個“副本”(已經去重,所以不完全是副本)。

每個文件的這些中間“副本”位於 Git 中,不同地稱為indexstaging area ,或(最近很少) cache 請注意,這些副本已准備好將 go 放入新的提交中,因為它們已經是僅 Git 的凍干格式。 與提交本身的副本不同,它們可以被替換。

這就是git add的全部內容。 git add命令意味着使某些文件的索引副本與工作樹副本匹配。 如果您更改了工作樹中的文件,則必須告訴 Git 將更新的文件復制回 Git 的索引。

這就是暫存文件 在任何時候,Git 的索引都有 Git 知道的每個文件的副本。 如果它在索引中,它就可以提交了——但它可能與當前提交中的文件相同,如果是,它已經被重復數據刪除了。 和 Git 可以很容易地看出它是相同的。

如果文件的索引副本與當前提交副本不同,或者是全新的,那么 go 進入下一個提交的內容與當前提交中的內容不同 Git 調用上演. 但是,如果索引副本與提交的副本相同,則 Git 什么也不說。

同時,文件的索引副本可能與工作樹副本匹配,也可能不匹配。 如果索引副本確實與工作樹文件匹配,則 Git 不會對此進行任何說明。 如果不是, Git 說文件是unstaged

這意味着一個文件可以同時為提交暫存和不為提交暫存,如果提交的副本(無法更改)與索引副本不匹配,並且索引副本與索引副本不匹配工作樹副本,您有一個文件,該文件既為 commit暫存,又不為 commit 暫存 您可以通過以下方式獲得此 state:

git checkout somebranch
edit file.ext             # change something in a file
git add file.ext          # copy the updated file back into Git's index
edit file.ext             # change something else in the same file

當您運行git commit時, Git 所做的是從當時 Git 索引中的任何內容進行新的提交。 因此,如果您現在有十個未暫存的文件,並且您git add其中六個然后運行git commit ,您將獲得一個新的提交,其中:

  • 六個文件與上一個提交不匹配(運行git commit之前的當前提交),但是
  • 所有其他文件與之前的提交匹配。

現在您已經做出了新的提交,新的提交就是當前的提交。 您是索引中的文件創建的,因此新的當前提交的所有文件都與索引中的所有文件匹配。 沒有文件被“暫存以供提交”,但是您沒有git add的四個文件仍然存在於您的工作樹中,與索引中相應的四個文件和當前提交中的這四個文件仍然不同。 所以這四個文件仍然是“未暫存提交”。

如果你喜歡,你現在可以git add這四個文件,將工作樹版本復制回 Git 的索引,然后git commit結果。 您現在有兩個以前沒有的新提交。 最后一個與您的工作樹匹配,因此當前提交、Git 的索引和您的工作樹都匹配:沒有文件被暫存,也沒有文件被取消暫存。

更多關於分支名稱

請注意,每次進行新提交時, Git 都必須更新當前分支名稱 假設您最初在master分支上,如下所示:

...--F--G--H   <-- master

現在您創建一個的分支名稱,例如feature 這個新名稱標識了提交H 我們將所有大寫字母的名稱HEAD添加到分支名稱之一,以顯示我們正在使用的分支名稱:

...--F--G--H   <-- feature (HEAD), master

現在我們將git add一些文件並進行新的提交。 它將獲得一個新的隨機外觀 hash ID; 我們稱之為I

...--F--G--H   <-- master
            \
             I

訣竅是 Git 現在將I的 hash ID 寫入名稱feature (即HEAD附加到),因此名稱現在指向I

...--F--G--H   <-- master
            \
             I   <-- feature (HEAD)

如果我們添加更多文件並git commit ,我們會得到另一個新的提交J

...--F--G--H   <-- master
            \
             I--J   <-- feature (HEAD)

請注意,每個提交都有每個文件的完整快照,因為它在您運行git commit時出現在 Git 的索引中。 當您使用git format-patch將提交變成補丁時,Git:

  • 從提交的級中提取文件(例如, H代表I );
  • 從提交中提取文件( I );
  • 比較提取的文件;
  • 告訴您哪些文件不同,為您提供將舊版本更改為新版本的秘訣。

由於這是一個可提交的補丁,Git 添加了一個 header 給它,給出了名稱和 email 的人的地址,為什么做出提交,一個適當的日期和時間標記的日志消息他們做出了承諾。 補丁本身出現在此 header 之后。

暫無
暫無

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

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