赞
踩
多分支模式可以将每个人所做的新的更改分离开来,极大地方便了项目管理,避免了未经评审或坏的更改进入项目。一旦评审通过,则可以将这些更改合并到项目中。
将一个分支的更改添加到另一个分支的一种方式是 git merge
。Git 有两种合并的执行方式,分别是 fast-forward 和 no-fast-forward。
现在你可能还不能理解这些,所以让我们一起来看看它们的差异。
--ff
)如果当前分支与即将合并的分支之间没有额外的提交,将采用 fast-forward 的合并方式。Git 很懒,所以默认使用 fast-forward 方式处理分支合并。这种合并方式不会创建新的提交,而是直接在当前分支中合并提交,且当旧分支被移除后,其分支信息也会被一并删除。
完美!现在 dev 分支上的所有更改都被合并到 master 分支。那么,no-fast-forward 有什么不同呢?
--no-ff
)如果当前分支与即将合并的分支之间没有额外的提交,那是相当的好。然而,这种情况很少。如果当前分支有待合并分支上所没有的提交更改,Git 将使用 no-fast-forward 合并方式。
执行 no-fast-forward 合并,Git 将在活动分支上创建一个新的提交,这个新的提交会同时指向活动分支和我们要合并的分支。
没什么大不了的,又是一个完美的合并!现在 master 分支已经包含了 dev 分支的所有更改了。
尽管 Git 擅长决定如何合并分支并向文件中添加更改,但也不是所有情况都能作出决定。比如我们想合并的两个分支都修改了同一个文件的相同行,或者一个分支删除了文件,但另一个分支却修改这个文件。
这种情况,Git 会询问你来决定应该保留哪个修改。举个例子,假如我们在两个分支中同时修改了 README.md 文件中的第一行。
现在你想将 dev 分支合并到 master 分支,将会出现合并冲突:would you like the title to be Hello!
or Hey!
?
Git 会找出冲突发生的位置,为了解决合并冲突,我们需要手动删除不想保留的更改,保存并重新添加文件,然后再提交更改。
耶!尽管解决合并冲突很烦人,但这是有意义的,因为 Git 不会帮我们去假设需要保留哪些更改。
我们知道使用 git merge
可以将一个分支的更改添加到另一个分支。除了这种方式,我们还可以使用 git rebase
命令来完成这个工作。
git rebase
命令将复制当前分支的所有提交,并将它们移动到指定分支上。
完美!我们现在可以在 dev 分支上使用 master 分支上进行的所有更改了。
与 merge 最大不同的是,rebase 总是保留当前分支的最新更改,不会尝试寻找哪些文件需要保留,哪些不需要。因此你不需要处理合并冲突,同时也会保持线性的 git 提交历史。
上面的例子展示了在 rebase master 分支的动作,但这里有一个大问题,导致我们通常不想这么处理。因为 git rebase
复制提交时会产生新的哈希值,从而影响了项目的提交历史。
当你在 feature 分支上工作时,并且 master 分支已经更新了,那么使用 rebase 是非常合适的。因为你可以在分支上获取所有更新,防止将来合并时发生冲突。
在 rebase 提交之前,我们还可以通过交互式 rebase 对提交进行修改。当你想修改正在使用的分支上的某些提交时,交互式 rebase 就非常有用。
我们可以对 rebase 的提交进行六种操作:
reword
: 修改提交附带消息edit
: 修改提交squash
: 将提交合并到上一个提交中fixup
: 将提交合并到上一个提交中,并且不保留提交的日志消息exec
: 在我们 rebase 的每一个提交的基础上运行命令drop
: 删除提交太棒了!这样,我们就可以完全控制提交。如果想删除提交,就可以 drop
它。
或者,我们要压缩多个提交以获得更清晰的历史记录,那也没问题!
使用交互式 rebase,你可以对要 rebase 的提交有更多控制,即使是在当前活动分支。
有时候我们提交了更改,但是因为一些原因不想要了。比如这是一个 WIP(Work In Process)提交,或者这个提交有 Bug。那么,我们就可以使用 git reset
对分支进行重置。
git reset
会删除所有当前暂存的文件,并让我们控制 HEAD
指向的位置。
soft reset 将 HEAD
移动到指定的提交,不会丢弃该提交之后引入的更改。
假如我们不想保留添加了 styles.css 文件的 9e78i
提交,也不想保留添加 index.js 文件的 035cc
提交。但是,我们想保留 styles.css 和 index.js 文件,那么使用 soft reset 就非常合适。
执行 git status
可以看到我们仍然可以访问先前提交所做的更改,即 styles.css 和 index.js 文件。这很棒,意味着我们可以修复这些文件的内容,后续再次提交。
有时候,我们不想保留某个提交引入的更改,不像 soft reset,我们不再需要访问它们了。Git 允许将其 reset 到指定的提交状态,包括工作目录和暂存文件都会被重置。
比如这里 Git 丢弃了 9e78i
和 035cc
提交引入的更改,并将其状态重置为 ec5be
提交时的状态。
撤销更改的另一种方法是执行 git revert
。通过还原某个提交,我们创建一个包含还原更改的新提交。
假如 ec5be
添加了 index.js 文件,后来我们意识到我们不再希望此提交引入此更改!于是,我们需要还原 ec5bc
提交。
完美!9e78i
提交还原了 ec5be
提交引入的更改。执行 git revert
对于撤销特定提交而不修改分支的历史记录非常有用。
当某个分支中的提交包含了当前活动分支需要更改时,可以使用 cherry-pick
命令。cherry-pick 一个提交时,会在活动分支上创建一个新的提交,其中包含了 cherry-pick 提交引入的更改。
假如 dev 分支的 76d12
提交在 index.js 文件添加了更改,而 master 分支刚好需要这些更改。但是 master 关心的只是这个提交,并不关心整个 dev 分支。
酷!现在 master 分支就包含了 76d12
提交的更改了。
如果我么有一个远程 Git 分支,例如 GitHub 上的一个分支,则可能该远程分支具有当前分支所没有的提交!这也许是由于另一个分支被合并到远程分支了,或者你的小伙伴提出了一个解决方案。
我们可以通过 git fetch
将远程分支的更改拉取到本地。fetch 操作只会下载新数据,并不会影响本地分支。
现在,我们可以看到自上次推送以来远程分支上所做的更改。本地已经拥有新数据了,接下来我们可以决定要如何处理这些数据。
尽管 git fetch
对于获取分支的远程信息非常有用,但是我们也可以执行 git pull
。git pull
实际上是 git fetch
和 git merge
两个命令的组合。当我们从远程分支 pull 更改时,实际上首先需要像 git fetch
那样拉取数据,之后将最新的更改自动合并到本地分支中。
太棒了!我们现在可以与远程分支完美同步,并具有所有最新的更改!
每个人都会犯错,这是 OK 的!有时候,你可能觉得自己已经把 git 仓库搞砸了,以致于只想完全删除它。
git reflog
是一个非常有用的命令,用于显示所有已执行动作的日志。包括 merge、reset、revert 等等对分支的任何更改操作。
如果你输入有误,可以先重置 HEAD
,然后再根据 reflog 的信息轻松地重做。
假如,我们不想合并 origin 分支。我们执行 git reflog
命令,看到合并前的状态是 HEAD@{1}
,于是我们通过 git reset
将 HEAD
指向 HEAD@{1}
。
可以看到,最新的操作已经被记录到日志
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。