【Git】Git高级

三、Git高级

1. 合并

当开发一个新功能时,需要切换到一个仓库,例如切换到上文提到的 feature 分支上。当新功能开发完成后,需要将其合并回 master 分支,可以通过切换到 master 分支,然后使用 git merge <branch name> 命令将新功能合并到 master 分支。为了实现上述的合并功能,Git 将 feature 分支中的所有变更集应用到 master 分支的顶部。

根据两个分支中更改的类型以及可能发生的冲突,在合并时会存在以下三种可能:

1.1 Fast forward merge(快速向前合并)
  • 从新建 feature 分支后,master 分支上没有产生任何的更改。master 分支一直指向 feature 分支创建前的最后一次 commit 的位置。在这种情况下合并,Git 将 master 分支的指针直接向前移动,如图所示(图片来自网络)。由于除了向前移动指针之外没有进行其他的操作,故该情形称为 Fast forward merge。

image


1.2 No-conflict merge(无冲突合并)
  • master 和 feature 两个分支都有产生变更,但两者之间的变更并不冲突。例如,两个分支中的变更修改的是不同的文件。Git 可以自动将来自 feature 分支的所有变更合并到到 master 分支,并创建包含这些变更的新 commit,然后 master 分支向前移动到该 commit 的位置,如图所示(图片来自网络)。

image


1.3 Conflicting merge(冲突合并)
  • master 和 feature 两个分支都有变更,且两者的变更存在冲突。在这种情况下,冲突的详情将保留在工作目录中,用户可以根据冲突详情进行修复和提交,或者使用 git merge –abort 取消合并。

  • 值得一提的事,如果两个分支中都进行了某些相同的变更,这种情况通常会导致冲突,但由于 Git 足够智能,实际上合并时可以检测到两者的变更是相同的,此时相当于进行了一次 Fast forward merge。



2. 冲突

  • 回滚(rolling back)和重放变更集(replaying change sets)的概念中包含了 Git 中一些更高级的特性,例如变基(rebasing)和择优挑选(cherry picking)。
  • 有时在 feature 分支上开发了一个新的功能时,master 分支上的开发也在同时进行,这时你还不想合并新功能到 master,随着时间的推移,两个分支之间的差异越来越大。为了避免两个分支差异过大给后续合并带来的一些不必要的麻烦,Git 提供了 rebase 和 cherry-picking 操作,可以将变更集从一个分支应用到另一个分支。
2.1 变基(Rebasing)
  • rebasing 相关的 Git 命令:

    git rebase <branchename> —— 将当前分支重新定位到给定<branchname>分支的尖端。
    git rebase --i(onto) —— 交互式参数变基( --onto 选项移动到指定的版本)。
    
  • 假设你正在 feature 分支上开发一个新的功能,并且需要将 master 分支上最新的变更合并到 feature 分支,以跟上最新的开发进度。上述操作称为变基(rebasing)feature 分支,即重新复位 feature 分支的基底。如图所示(图片来自网络)

image

  • 如果上述操作导致了冲突,rebase 会在第一个发生冲突的位置停止,并将冲突状态留在工作目录中供用户修复,接着用户可以继续或中止 rebase。

  • 如果想要将分拆点在 master 分支上向上移动到指定的版本, 可以使用 --onto 选项指定版本ID。


2.2 择优挑选(Cherry picking)
  • Cherry picking 相关的 Git 命令:

    git cherry-pick <commit_id> —— 挑选commit_id复制到其它分支
    
  • 假设你现在正在 feature 分支上开发一个功能,并且已经做一些应该立即放到 master 分支中的更改。这些更改可能是一个错误的修复,或者是一个很酷的新功能,但你现在还不想将整个 feature 分支合并到 master 分支,或者对 feature 分支进行变基。此时,Git 允许你使用则有挑选(Cherry picking)功能将更改集从一个分支复制到另一个分支。

image


2.3 恢复(Revert)
  • Revert 相关的 Git 命令:

    git revert —— 恢复一个补丁
    
  • revert是用于“反做”某一个版本,以达到撤销该版本的修改的目的。比如,我们commit了三个版本(版本一、版本二、 版本三),突然发现版本二不行(如:有bug),想要撤销版本二,但又不想影响撤销版本三的提交,就可以用git revert 命令来反做版本二,生成新的版本四,这个版本四里会保留版本三的东西,但撤销了版本二的东西。如下图所示(图片来自网络):

image

  • 适用场景: 如果我们想撤销之前的某一版本,但是又想保留该目标版本后面的版本,记录下这整个版本变动流程,就可以用这种方法。另外,如果想直接回退到某个版本并不在乎保留该目标版本后面的内容,则直接用git reset --hard commit_id

2.4 暂存工作现场(stash)
  • stash相关的Git命令:

    git stash —— 在当前分支使用保存现场作业,切换到别的分支修bug
    git stash list —— 修改完bug,切换回分支,查看刚才保存的现场作业
    git stash pop —— 恢复下现场作业后进行修改
    
  • stash的功能,可以把当前分支的工作现场“存储”起来,等解决其它分支的问题以后恢复现场继续工作。主要场景是,在分支dev开发一个新功能,突然接到老板命令master分支上需要修改个Bug。这个时候就可以在dev分支上使用git stash保存现场工作,然后切换到master分支用git checkout -b <bug_001> 命令创建修Bug的分支进行修改,修完后合并到master,删除分支bug_001。接着要做自己的现场工作了,切换到分支dev,用命令git stash list查看刚才保存的现场作业,再恢复下git stash pop就能继续开发了。



3. 多人协作(Collaboration)

  • Collaboration 涉及到的相关 Git 命令:

    git clone —— 将远程仓库“克隆”到本地。
    git remote add —— 添加一个名为给定连接 URL的远程仓库 。
    git fetch —— 从远程仓库获取远程跟踪分支的变更到本地。
    git pull —— 获取远程仓库的变更,并合并到本地仓库。该命令是 fetch 与 merge 两个命令的组合。
    git push —— 将本地分支的更改通过远程跟踪分支推送到远程仓库。
    
  • push 操作有一个保护措施,即只有当 push 操作在远程仓库的分支中触发的合并方式是 fast-forward merge,该操作才会成功,否则会中止。如果不是 fast-forward merge,那么说明远程分支上已经有来自其他仓库或提交者提交的一些更改。Git 中止 push 操作并保持原样。然后您必须先 fetch 远程仓库上的更改,将它们合并到你的本地分支中,最后再次重新尝试 push。

  • 如果你尝试直接 push 变更到有其他人也在跟踪的仓库上时,这可能会对分支管理造成混乱,因此 Git 会警告并告诉你,应该首先使用 pull 操作将远程分支的状态同步到本地。因此养成良好的使用习惯是避免代码冲突的有效方式,良好的习惯有以下:

    • 养成良好的操作习惯,先pull在修改,修改完立即commitpush
    • 一定要确保自己正在修改的文件是最新版本的
    • 各自开发各自的模块
    • 如果要修改公共文件,一定要先确认有没有人正在修改
    • 下班前一定要提交代码,上班第一件事拉取最新代码
    • 一定不要擅自修改同事的代码
posted @ 2022-04-27 12:09  陈景中  阅读(146)  评论(0编辑  收藏  举报