[英]Git: Pulling a rebased branch
讓我描述一下我的情況:
Blond 先生和 Orange 先生正在處理分支 A,該分支在提交 M1 時從主分支分支出來。 分支 A 有 2 個提交:A1 和 A2。
M1
\
\
A1 - A2
與此同時,Orange 先生在主分支 M2 和 M3 上提交並推送了另外 2 個提交。
M1 - M2 - M3
\
\
A1 - A2
Blond 先生從遙控器中拉出,過了一會兒決定重新設置到 master 分支上:
M1 - M2 - M3
\ \
\ \
A1 - A2 A1` - A2`
現在 A1` 和 A2` 是在 Mr blond's 本地存在的 rebase 提交,並且 A1 和 A2 遠程存在。 Blond 先生推動他的提交,使用-f強制他的更改和“重寫”歷史。 現在遠程存儲庫如下所示:
M1 - M2 - M3
\
\
A1` - A2`
但奧蘭治先生也在 A 分公司工作。 他的本地存儲庫仍然如下所示:
M1 - M2 - M3
\
\
A1 - A2
橙先生需要做什么才能與遠程倉庫的A分支同步?
正常的拉動是行不通的。 pull -f會在本地強制從遠程進行更改嗎? 我知道刪除 A 的本地版本並從遠程存儲庫中再次將其帶入可以解決問題,但這似乎不是實現這一目標的好方法。
如果 Orange 先生不介意丟失他的更改,他可以從服務器獲取,然后git checkout A
進入他的本地A
分支,然后(假設遠程被命名為“origin”) git reset --hard origin/A
將他A
重置為遙控器的A
所在的位置。
如果他擔心丟失更改,他可以使用git merge origin/A
合並服務器的更改以解決它們(從他自己的A
分支,並再次假設遠程被命名為“origin”)。 這將在他的和遠程的A
分支之上進行一個新的提交,並將兩者的更改合並在一起。 然后可以將其推回遙控器。
我的建議(或者,“如果我是 Orange 先生,我會怎么做”)是從git fetch
開始。 現在我將在我的 repo 中有這個,這是 Blond 先生在他的 rebase 之后和他運行“git push -f”之前所擁有的。
M1 - M2 - M3
\ \
\ \
A1 - A2 A1' - A2'
一個重要的區別是,我的本地標簽A
指向 rev A2,遠程標簽remotes/origin/A
指向 A2'(Blond 先生反過來說,本地標簽A
指向 A2' 和remotes/origin/A
指向 A2)。
如果我一直在處理名為“A”的分支副本,我將改為:
M1 ---- M2 ---- M3
\ \
\ \
A1 - A2 - A3 A1' - A2'
(我的本地標簽指向 A3 而不是 A2;或 A4 或 A5 等,具體取決於我應用了多少更改。)現在我所要做的就是將我的 A3(如果需要,還有 A4 等)重新定位到 A2' . 一種明顯的直接方式:
$ git branch -a
master
* A
remotes/origin/master
remotes/origin/A
$ git branch new_A remotes/origin/A
$ git rebase -i new_A
然后完全刪除 revs A1 和 A2,因為修改后的在 new_A 中作為 A1' 和 A2'。 或者:
$ git checkout -b new_A remotes/origin/A
$ git format-patch -k --stdout A3..A | git am -3 -k
( git am -3 -k
方法在git-format-patch
手冊頁中有描述)。
這些確實需要弄清楚 Blond 先生在他做他的rebase
之前沒有什么,即識別 A1、A2、A3 等。
如果第二種方法成功,我最終會得到:
M1 ---- M2 ---- M3
\ \
\ \
A1 - A2 - A3 A1' - A2' - A3'
我的分支名稱new_A
指向 A3'(我現有A
分支仍然指向舊的 A3)。 如果我使用第一種方法並且它成功了,我最終會得到同樣的結果,只是我現有的分支名稱A
現在將指向 A3'(而且我沒有 A1-A2-A3 的舊分支的名稱,甚至雖然它仍然在我的回購中;找到它需要通過 reflogs 或類似的)。
(如果我的 A3 需要修改為 A3',當然,交互式變基和“git am”方法都需要我的工作。)
當然也可以只git merge
(如 Gary Fixler 的回答),但這將創建一個合並提交(“M”,沒有數字,如下)並保持 A1 和 A2 的轉速可見,給出:
M1 ---- M2 ---- M3
\ \
\ \
A1 - A2 - A3 A1' - A2' -- M
\_______________/
如果要保留原來的A1和A2,這是好事; 如果你想擺脫它們,那是一件壞事。 所以“做什么”取決於“你想要的結果是什么”。
編輯添加:我更喜歡 format-patch 方法,因為它保留了我的舊 A 分支名稱,同時我確保一切都很好。 假設一切正常並且很好,這是最后幾個步驟:
$ git branch -m A old_A
$ git branch -m new_A A
然后,如果 old_A 可以完全放棄:
$ git branch -D old_A
或者,等效地,從分支刪除開始,然后將 new_A 重命名為 A。
(編輯:另見git rebase --onto
文檔,以將 A3 等重新定位到 new_A 分支上。)
出於配置目的,我在兩個虛擬機上同時開發。 結果,我經常在一台機器上進行 rebase,並且需要將更改毫無困難地出現在另一台機器上。
假設我的分支名為feature/my-feature-branch
。 在第一個 VM 上完成 rebase 后,我在第二個 VM 上執行 git fetch。 出現以下消息:
$ git status
On branch feature/my-feature-branch
Your branch and 'origin/feature/my-feature-branch' have diverged,
and have 21 and 24 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
好吧,不要執行 git pull,因為在經過一番大驚小怪之后,您最終會得到一個毫無意義的合並提交。
相反,運行
git rebase -i origin/feature/my-feature-branch
一旦文本編輯器彈出,刪除所有提交,並將其替換為以下內容(這使得 rebase 完成而不保留任何提交)。
exec echo test
如果您確實有需要保留的提交,那么可以在此處應用這些提交。 在任何一種情況下,rebase 都會完成,現在兩台機器再次同步,如下所示:
$ git pull
Already up-to-date.
$ git push
Everything up-to-date
除非我誤解了這個問題,否則奧蘭治先生的答案是git pull --rebase
。
如果我們假設 A1 和 A2 所做的更改與 A1' 和 A2' 相同(即使它們的提交哈希值不同),那么 Orange 先生可以不再擁有
M1 - M2 - M3
\
\
A1 - A2
本地擁有
M1 - M2 - M3
\
\
A1` - A2`
通過要么做
git pull --rebase
或者
git branch -d A
git checkout A
如果我們假設,如上所述,A1 和 A2 所做的更改是相同的,並且 Orange 先生進行了額外的提交,那么他將在本地擁有
M1 - M2 - M3
\
\
A1 - A2 - A3O
和起源將是
M1 - M2 - M3
\
\
A1` - A2`
再說一次,奧蘭治先生可以到達
M1 - M2 - M3
\
\
A1` - A2` - A3O
和
git pull --rebase
如果我們假設,如上所述,A1 和 A2 所做的更改是相同的,Orange 先生做了一個額外的提交,而 Blonde 先生做了一個額外的提交,那么 Orange 先生將在本地擁有這個
M1 - M2 - M3
\
\
A1 - A2 - A3O
並且,假設 Blonde 先生已經推動,起源將是
M1 - M2 - M3
\
\
A1` - A2` - A3B
奧蘭治先生可以到達
M1 - M2 - M3
\
\
A1` - A2` - A3B - A3O
通過做
git pull --rebase
不過,這一次,他可能需要解決沖突。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.