重写项目历史
git commit --amend
git commit --amend 命令是修复最新提交的便捷方式。
合并缓存的修改和上一次的提交,用新的快照替换上一个提交,缓存区没有文件时运行这个命令可以用来编辑上次提交的提交信息,而不会更改快照。
讨论
仓促的提交在你日常开发过程中时常会发生。很容易就忘记了缓存一个文件或者弄错了提交信息的格式。--amend 标记是修复这些小意外的便捷方式
不要修复公共提交
我们说过永远不要重设 reset和其他开发者共享的提交。对于修复也是一样:永远不要修复一个已经推送到公共仓库中的提交.
例子
我们编辑了一些希望在同一个快照中提交的文件,但我们忘记添加了其中的一个。修复错误只需要缓存那个文件并且用 --amend 标记提交
# 编辑 hello.py 和 main.py
git add hello.py
git commit
# 意识到你忘记添加 main.py 的更改
git add main.py
git commit --amend --no-edit
#编辑器会弹出上一次提交的信息,加入 --no-edit 标记会修复提交但不修改提交信息
git rebase
是将分支移到一个新的基提交的过程。过程一般如下所示:
从内容的角度来看,rebase 只不过是将分支从一个提交移到了另一个。但从内部机制来看,Git 是通过在选定的基上创建新提交来完成这件事的——它事实上重写了你的项目历史。理解这一点很重要,尽管分支看上去是一样的,但它包含了全新的提交。
用法
git rebase <base>
将当前分支 rebase 到 <base>
,这里可以是任何类型的提交引用(ID、分支名、标签,或是 HEAD 的相对引用)。
讨论
rebase 的主要目的是为了保持一个线性的项目历史。比如说,当你在 feature 分支工作时 master 分支取得了一些进展,需要将 master上 的进展合并到当前的分支上:
要将你的 feature 分支整合进 master 分支,你有两个选择:直接 merge,或者先 rebase 后 merge。
前者会产生一个三路合并(3-way merge)和一个合并提交,而后者产生的是一个快速向前的合并以及完美的线性历史
rebase 是将上游更改合并进本地仓库的通常方法。
你每次想查看上游进展时,用 git merge拉取上游更新会导致一个多余的合并提交。
在另一方面,rebase 就好像是说「我想将我的更改建立在其他人的进展之上」。
不要 rebase 公共历史
git commit --amend 和 git reset 一样,你永远不应该 rebase 那些已经推送到公共仓库的提交,rebase 会用新的提交替换旧的提交,你的项目历史会像突然消失了一样。
例子
# 开始新的功能分支
git checkout -b new-feature master
# 编辑文件后提交
git commit -a -m "Start developing a feature"
在 feature 分支开发了一半的时候,我们意识到项目中有一个安全漏洞:
# 基于master分支创建一个快速修复分支
git checkout -b hotfix master
# 编辑文件后并提交
git commit -a -m "Fix security hole"
# 回到 master
git checkout master
# 将 hotfix 合并到 master
git merge hotfix
# 删除分支 hotfix
git branch -d hotfix
将 hotfix 分支并回之后 master,我们有了一个分叉的项目历史。
我们用 rebase 整合 feature 分支以获得线性的历史,而不是使用普通的 git merge。
# 切回 new-feature 分支
git checkout new-feature
# 将 master 的分支合并到 new-feature分支上
git rebase master
它将 new-feature 分支移到了 master 分支的末端,现在我们可以在 master 上进行标准的快速向前合并了
# 切回 master
git checkout master
# 将 new-feature 的分支合并到maerge
git merge new-feature
git reflog
Git 用引用日志这种机制来记录分支顶端的更新
用法
#显示本地仓库的引用日志。
git reflog
讨论
每次当前的 HEAD 更新时(如切换分支、拉取新更改、重写历史或只是添加新的提交),引用日志都会添加一个新条目。