12.3 回到未来
电影《回到未来》(Back to Future)第二集,老毕福偷走时光车,到过去(1955年)给了小毕福一本书,导致未来大变。
图 12-1 布朗博士正在解释为何产生两个平行的未来
Git这一台“时光机”也有这样的能力,或者说也具有这样的行为。更改历史提交(SHA1哈希值变更)后,即使后续提交的内容和属性都一致,但是因为后续提交中有一个属性是父提交的SHA1哈希值,所以一个历史提交的改变会引起连锁变化,导致所有的后续提交都发生变化,形成两条平行的时间线:一个是变更前的提交时间线,另外一条是更改历史后新的提交时间线。
把此次实践比喻成一次电影(《回到未来》)拍摄的话,舞台依然是之前的DEMO版本库,而剧本是这样的。
角色:最近的六次提交。分别依据提交顺序,编号为A、B、C、D、E、F。
$git log—oneline-6
b6f0b0a modify hello.h#F
48456ab add hello.h#E
3488f2c move.gitignore outside also works.#D
b3af728 ignore object files.#C
d71ce92 Hello world initialized.#B
c024f34 README is from welcome.txt.#A
坏蛋:提交D。
即不再需要对.gitignore文件进行移动的提交,或者这个提交将和前一次提交
12.3.1 时间旅行一
就是在特定命名空间建立“固定”的引用,用于对提交进行标识)。
$git tag F
$git tag E HEAD^
$git tag D HEAD^^
$git tag C HEAD^^^
$git tag B HEAD~4
$git tag A HEAD~5
通过日志,可以看到被标记的6个提交。
$git log—oneline—decorate-6
b6f0b0a(HEAD,tag:F,master)modify hello.h
48456ab(tag:E)add hello.h
3488f2c(tag:D)move.gitignore outside also works.
b3af728(tag:C)ignore object files.
d71ce92(tag:hello_1.0,tag:B)Hello world in itialized.
c024f34(tag:A)README is from welcome.txt.
1.现在演出第一幕:干掉坏蛋D
(1)执行git checkout命令,暂时将HEAD头指针切换到C。
切换过程显示处于非跟踪状态的警告,没有关系,因为剧情需要。
$git checkout C
Note:checking out 'C'.
You are in 'detached HEAD' state.You can look around,make experimental
changes and commit them,and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create,you may
do so(now or later)by using-b with the checkout command again.Example:
git checkout-b new_branch_name
HEAD is now at b3af728…ignore object files.
(2)执行拣选操作将E提交在当前HEAD上重放。
因为E和master^显然指向同一角色,因此可以用下面的语法。
$git cherry-pick master^
[detached HEAD fa0b076]add hello.h
1 files changed,1 insertions(+),0 deletions(-)
create mode 100644 src/hello.h
(3)执行拣选操作将F提交在当前HEAD上重放。
F和master也具有相同指向。
$git cherry-pick master
[detached HEAD f677821]modify hello.h
2 files changed,2 insertions(+),0 deletions(-)
(4)通过日志可以看到坏蛋D已经不在了。
2.幕布拉上,后台重新布景
为了第二幕能够顺利演出,需要将master分支重新置回到提交F上。执行下面的操作完成“重新布景”。
$git checkout master
Already on 'master'
$git reset—hard F
HEAD is now at b6f0b0a modify hello.h
$git log—oneline—decorate-6
b6f0b0a(HEAD,tag:F,master)modify hello.h
48456ab(tag:E)add hello.h
3488f2c(tag:D)move.gitignore outside also works.
b3af728(tag:C)ignore object files.
d71ce92(tag:hello_1.0,tag:B)Hello world initialized.
c024f34(tag:A)README is from welcome.txt.
布景完毕,大幕即将再次拉开。
3.现在演出第二幕:坏蛋D被感化,融入社会
(1)执行git checkout命令,暂时将HEAD头指针切换到坏蛋D。
切换过程显示处于非跟踪状态的警告,没有关系,因为剧情需要。
$git checkout D
Note:checking out 'D'.
You are in 'detached HEAD' state.You can look around,make experimental
changes and commit them,and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create,you may
do so(now or later)by using-b with the checkout command again.Example:
git checkout-b new_branch_name
HEAD is now at 3488f2c…move.gitignore outside also works.
(2)悔棋两次,以便将C和D融合。
$git reset—soft HEAD^^
(3)执行提交,提交说明重用C提交的提交说明。
$git commit-C C
[detached HEAD 53e621c]ignore object files.
1 files changed,3 insertions(+),0 deletions(-)
create mode 100644.gitignore
(4)执行拣选操作将E提交在当前HEAD上重放。
$git cherry-pick E
用法1:git rebase—onto<newbase><since><till>
用法2:git rebase—onto<newbase><since>[HEAD]
用法3:git rebase[—onto<since>]<since><till>
用法4:git rebase[—onto<since>]<since>[HEAD]