7.13 替換

2018-02-24 15:22 更新

替換

Git 對象是不可改變的,但它提供一種有趣的方式來用其他對象假裝替換數(shù)據(jù)庫中的 Git 對象。

replace?命令可以讓你在 Git 中指定一個對象并可以聲稱“每次你遇到這個 Git 對象時,假裝它是其他的東西”。 在你用一個不同的提交替換歷史中的一個提交時,這會非常有用。

例如,你有一個大型的代碼歷史并想把自己的倉庫分成一個短的歷史和一個更大更長久的歷史,短歷史供新的開發(fā)者使用,后者給喜歡數(shù)據(jù)挖掘的人使用。 你可以通過用新倉庫中最早的提交?replace老倉庫中最新的提交來連接歷史,這種方式可以把一條歷史移植到其他歷史上。 這意味著你不用在新歷史中真正替換每一個提交(因為歷史來源會影響 SHA 的值),你可以加入他們。

讓我們來試試吧。 首先獲取一個已經(jīng)存在的倉庫,并將其分成兩個倉庫,一個是最近的倉庫,一個是歷史版本的倉庫,然后我們將看到如何在不更改倉庫 SHA 值的情況下通過?replace?命令來合并他們。

我們將使用一個擁有 5 個提交的簡單倉庫:

$ git log --oneline
ef989d8 fifth commit
c6e1e95 fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit

我們想將其分成拆分成兩條歷史。 第一個到第四個提交的作為第一個歷史版本。 第四、第五個提交的作為最近的第二個歷史版本。

Figure 7-29.

現(xiàn)在我們可以把這個新的?history?分支推送到我們新倉庫的?master?分支:

$ git remote add project-history https://github.com/schacon/project-history
$ git push project-history history:master
Counting objects: 12, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (12/12), 907 bytes, done.
Total 12 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (12/12), done.
To git@github.com:schacon/project-history.git
 * [new branch]      history -> master

這樣一來,我們的歷史版本就發(fā)布了。 稍難的部分則是刪減我們最近的歷史來讓它變得更小。 我們需要一個重疊以便于用一個相等的提交來替換另一個提交,這樣一來,我們將截斷到第四、五個提交。

$ git log --oneline --decorate
ef989d8 (HEAD, master) fifth commit
c6e1e95 (history) fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit

在這種情況下,創(chuàng)建一個能夠指導(dǎo)擴展歷史的基礎(chǔ)提交是很有用的。 這樣一來,如果其他的開發(fā)者想要修改第一次提交或者其他操作時就知道要做些什么,因此,接下來我們要做的是用命令創(chuàng)建一個最初的提交對象,然后將剩下的提交(第四、第五個提交)變基到它的上面。

為了這么做,我們需要選擇一個點去拆分,對于我們而言是第三個提交(SHA 是?9c68fdc)。因此我們的提交將基于此提交樹。我們可以使用?commit-tree?命令來創(chuàng)建基礎(chǔ)提交,這樣我們就有了一個樹,并返回一個全新的、無父節(jié)點的 SHA 提交對象。

$ echo 'get history from blah blah blah' | git commit-tree 9c68fdc^{tree}
622e88e9cbfbacfb75b5279245b9fb38dfea10cf
NOTE

commit-tree?命令屬于底層指令。有許多指令并非直接使用,而是被?其他的?Git 命令用來做更小一些的工作。有時當(dāng)我們做一些像這樣的奇怪事情時,它們允許我們做一些不適用于日常使用但真正底層的東西。更多關(guān)于底層命令的內(nèi)容請參見?底層命令和高層命令

Figure 7-31.

我們已經(jīng)用基礎(chǔ)提交重寫了最近的歷史,基礎(chǔ)提交包括如何重新組成整個歷史的說明。 我們可以將新歷史推送到新項目中,當(dāng)其他人克隆這個倉庫時,他們僅能看到最近兩次提交以及一個包含上述說明的基礎(chǔ)提交。

現(xiàn)在我們將以想獲得整個歷史的人的身份來初次克隆這個項目。 在克隆這個截斷后的倉庫后為了得到歷史數(shù)據(jù),需要添加第二個遠(yuǎn)程的歷史版本庫并對其做獲取操作:

$ git clone https://github.com/schacon/project
$ cd project

$ git log --oneline master
e146b5f fifth commit
81a708d fourth commit
622e88e get history from blah blah blah

$ git remote add project-history https://github.com/schacon/project-history
$ git fetch project-history
From https://github.com/schacon/project-history
 * [new branch]      master     -> project-history/master

現(xiàn)在,協(xié)作者在?master?分支中擁有他們最近的提交并且在?project-history/master?分支中擁有過去的提交。

$ git log --oneline master
e146b5f fifth commit
81a708d fourth commit
622e88e get history from blah blah blah

$ git log --oneline project-history/master
c6e1e95 fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit

為了合并它們,你可以使用?git replace?命令加上你想替換的提交信息來進(jìn)行替換。 這樣一來,我們就可以將 master 分支中的第四個提交替換為?project-history/master?分支中的“第四個”提交。

$ git replace 81a708d c6e1e95

現(xiàn)在,查看?master?分支中的歷史信息,顯示如下:

$ git log --oneline master
e146b5f fifth commit
81a708d fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit

很酷,是不是?不用改變上游的 SHA-1 我們就能用一個提交來替換歷史中的所有不同的提交,并且所有的工具(bisect,blame?等)也都奏效。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號