[英]how to merge branch into master on the created commit
我有這個場景,我從 master 創建了一個分支 A,其中 master 負責人在1234
提交 id
現在一些開發人員將更多的分支和提交推送到 master 中,現在 master 負責人在789
提交 id 上。
是否可以在提交1234
時將分支 A 合並到 master 中?
不要試圖把這個比喻推得太遠(因為它會崩潰),但這有點像問你是否可以將你的 package 放在中國的貨船上,因為船在洛杉磯的港口。 你可以,但你得先把船弄回中國。
讓我們看看 Git 是如何工作的,而不是上面的笨拙的類比。 Git 都是關於提交的,而且——正如你在這里正確描述的——這些提交被編號。 不過,這個數字並不是簡單的連續計數數字——例如,提交 #52 后面沒有提交 #53——而是它們是大的、丑陋的、看起來隨機的 hash ID。 所以我喜歡用單個大寫字母來表示它們:
...--G--H <-- master
在這里,名稱master
指向提交H
。 H
是master
上的最新提交。 提交H
本身向后到達較早的提交G
,后者向后到達另一個較早的提交,依此類推。
在您的情況下,您創建了一個新名稱也指向提交H
,然后進行了一些新提交:
I--J <-- your-branch
/
...--G--H <-- master
不幸的是,從那時起,其他人向master
添加了更多提交,如下所示:
I--J <-- your-branch
/
...--G--H
\
K--L <-- master
您現在詢問是否使用git merge
。
當我們確實使用git merge
時,我們這樣做是因為我們想合並工作。 也就是說,你從提交H
開始——一些特定的文件集,永遠存儲在一個帶有一些丑陋的大 hash ID 的提交中。 您更改了一個或兩個文件並進行了新的提交,它得到了一些我稱之為I
的其他大而丑陋的隨機 ID,並且可能更改了另一個或兩個文件(或相同的文件或兩個)並進行了另一個提交J
. 所以在H
和J
之間,你做了一些工作,導致一些文件發生了一些變化。
Git 可以通過將提交H
中的快照(從您開始的所有時間凍結的文件集)與您最近提交中的快照進行比較,向您展示您所做的(總結為一組大的一次性更改), I
。 這將有如下指令:在文件main.py
中,刪除第 47 行,並在第 300 行之后添加一些行。
Git 還可以通過比較H
中的快照中的內容(注意此快照在兩個分支上共享)與提交K
中master
上的最新快照中的內容,向您展示其他人做了什么。 這可能包含更改 README.md 中的第 7 行README.md
類的指令,以及諸如在main.py
中的第 100 行添加一行的指令。
git merge
可以為您或任何人做的就是結合這些更改。 也就是說,如果他們接觸README.md
而你沒有接觸,Git 將保留他們的更改。 如果您觸摸了Documentation/info.md
而他們沒有,Git 將保留您的更改。 如果您和他們都修改main.py
, Git 將嘗試保留對該文件的兩組更改。
如果 Git可以自己組合所有這些更改,則 Git 將自己進行一個新的提交。 這個新的提交將包含來自H
中快照的所有文件(通用起點)作為其快照,並應用組合更改,以便 Git 保留您的更改並添加他們的更改,或者 - 如果您更喜歡查看它方式 - 保留他們的更改並添加您的。 結果都是一樣的,看起來像這樣:
I--J
/ \
...--G--H M
\ /
K--L
我在這里留下的是哪個分支擁有新的提交M
。 有兩個名稱——master 和your-branch
master
並且 Git 只會更新這兩個名稱之一,以便它指向新的提交M
。 另一個名稱將繼續指向提交J
或提交L
(無論它之前指向哪個)。
我還省略了另一個細節,這有時確實很重要:因為提交M
有兩個反向鏈接,或者parents ,指向提交J
和L
,所以這兩個中的一個首先出現。 另一個是第二個,盡管對於 Git,這只是“不是第一”。 稍后, --first-parent
標志有時對於挑選“第一個”父級很有用。 無論您如何進行合並, M
中的快照都是相同的,但是第一父級的選擇取決於您git switch
到哪個分支,以及您給git merge
的名稱:
git switch master
git merge your-branch
給我們:
I--J <-- your-branch
/ \₂
...--G--H M <-- master
\ /¹
K--L
也就是說, master
是指向M
的名稱,而第一個父級現在是L
。
這通常是大多數人想要做的——除非他們想使用git rebase
。
是否可以在 [shared] 提交時將 [my branch] 合並到 master 中?
不完全是,因為無論你做什么, master
最終都需要指向除H
之外的其他提交。
您可以“彈出”提交KL
,如下所示:
I--J <-- your-branch
/
...--G--H <-- master
\
K--L [abandoned]
這樣做的問題是提交K
和L
現在丟失了。 它們並沒有消失——它們仍然在存儲庫中——但是 Git 通過以分支名稱開頭來查找提交。 用於查找提交L
的名稱master
。 從L
, Git 可以向后工作到K
。
Git無法繼續工作。 Git 總是向后工作。 因此,一旦您將master
向后移動兩步,指向H
, Git 就再也找不到K
了。 即使 Git可以找到K
,也無助於找到L
。 所以這兩個提交現在被“放棄”了。 這丟掉了他們的工作。 這不是合並的目的:合並有助於在添加您的工作時保留其他人的工作,或者等效地,在添加其他人的同時保留您的工作。
無需贅述,變基背后的想法是我們希望將一些提交復制到一些新的和改進的提交中。 在這種特殊情況下,您可能希望接受您認為非常好的IJ
提交,並通過進行兩次新的提交來“改進”它們——由於目前還沒有明顯的原因,我們將其稱為I'
(I- prime) 和J'
—很像I
和J
。
新的和改進I'
與原來的I
之間的區別在於兩部分:
I'
將不向后鏈接到H
,而是鏈接到K
。I'
作為它的快照,不是H
中隨您的更改而修改的快照,而是K
中隨您的更改而修改的快照。 I'
的rest將與I
完全相同,包括提交日志消息。 現在讓我們畫出I'
:
I--J <-- your-branch
/
...--G--H
\
K--L <-- master
\
I' <-- temporary-branch
(The underlying Git command that produces I'
from I
is git cherry-pick
. We have to have Git do this on a temporary branch , because Git needs to be able to find all the commits, including both the old ones and the new ones正在構建。rebase 命令隱藏了這種復雜性的大部分,但是因為 Git 在某些事情上很糟糕,所以有時你會看到這一切。)
一旦 Git 復制了I
到I'
,我們需要讓 Git 復制J
到J'
:
I--J <-- your-branch
/
...--G--H
\
K--L <-- master
\
I'-J' <-- temporary-branch
一旦將your-branch
上的所有提交復制到新的臨時分支,然后我們將 Git 從提交J
中“剝離分支名稱” your-branch
並將其粘貼到提交J'
— 剛剛制作的最后一個副本 Git —並丟棄臨時名稱:
I--J [abandoned]
/
...--G--H
\
K--L <-- master
\
I'-J' <-- your-branch
因為 Git 按分支名稱查找提交,所以如果我們現在查看這個存儲庫,看起來好像我們等到提交L
存在,然后才開始工作並生成提交IJ
。 我們將看到提交I'
和J'
,而不是I
和J
,但除非我們記住實際的 hash ID——而且沒有人這樣做過——否則我們不會注意到我們現在正在查看兩個不同的提交。 (Git 會知道。Git 查看原始的 hash ID。但我們會忘記,因為這是人類所做的。)
因為 rebase用新的提交替換了舊的提交(新的並且據說是改進的),所以它並不總是合適的。 特別是,如果你已經將你的I
和J
提交給了其他人,並且他們依賴於他們——包括他們的 hash ID——然后說“把它們扔掉,改用這些新的和改進的”會讓他們做額外的工作. 有時這很好。 (例如,如果他們已經同意這樣做,那也沒關系。)有時不是。
但是,如果您從未將這些提交給任何其他人,他們甚至不會知道您這樣做了。 所以對於那個特殊的情況——“私人”提交——只要你知道你在做什么,rebase 是安全的。
變基的好處是,最后,Git 的歷史“看起來更簡單”,人們可以用更少的精神負擔來思考它。 缺點是它不是真正發生的事情:如果你在 rebase 期間破壞了某些東西,它可能很難調試,這是一個謊言。 是一個善意的謊言讓事情變得更好,還是一個丑陋的大謊言導致死亡和毀滅? 我們不知道,您可能還不知道,直到您嘗試一下。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.