git commands 手册

前言

aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy8xODA4NzQzNS1iZjJhOTk2ZWY1MGEyMWIwLmpwZw.jfif)git通用流程图src=http___www.1004619.com_p.php_p=http___img1.sycdn.imooc.com_59c31e4400013bc911720340.png&refer=http___www.1004619.jfif

多人协作冲突

1.什么是Git多人协同开发

当开发一个大型项目时通常都是许多人进行合作,每个人负责项目的一部分,Git是实现多人协同开发最常见的工具,但是对于刚接触Git的人来说,多人协同开发会遇见很多问题,这篇博客的内容主要就是为了给出多人协同开发的正确步骤,并对这个过程中遇到的问题进行解释和解决。

那么多人协同开发时如何避免代码冲突呢?

我们先了解一下多人协作开发的流程吧!

2.多人协作开发的准备工作

  • 新建一个仓库
  • 创建主分支,即上传项目的初始内容到master分支
  • 团队内成员进行分工(各个成员之间负责的内容用尽量不冲突)

3.开发阶段

  • 每个成员将远程仓库主(master)分支的内容clone下来
  • 按照分工进行自己负责的工作

4.提交阶段(冲突产生阶段)

(1)、每个成员在完成自己的工作后,首先需要注意远程仓库的变化

方式一:拉取远程分支(git pull指令)

git pull指令可以理解为两个步骤:

  • 获取远程分支
  • 将获取的远程分支与本地分支合并

方式二:获取远程分支(git fetch指令)

git fetch指令的理解:

  • 获取远端指定分支的最新版到本地(即在本地创建一个新分支内容为远端指定分支的最新版)
  • 获取分支后就可以比较、查看远程分支的内容,随后若想push,可选择与获取的分支进行merge(合并)再push。

(2)、获取远程仓库的最新版本与本地进行合并

合并时会产生冲突问题:合并冲突

产生情况(3种):

  • 两个人对同一项目的不同文件进行了修改
  • 两个人对同一项目的同一文件的不同区域进行了修改
  • 对同一项目的同一文件的同一区域进行了不同修改

思考:那么上面3种情况中哪种会产生冲突呢?

下面将揭晓答案:

前面两种都是可以由git进行自动合并的,而第三种情况是无法自动合并的,需要手动合并(第三种会产生冲突);

问题1:什么是自动合并呢?

合并本质上可以理解为将两个人(分支)对项目的基础的修改整合到一块,注意是对项目的修改。上述三种情况的前两种是两个人对项目的不同区域进行修改,互不干扰,所以Git可以自动的将两个人对项目的修改整合到一起

问题2:什么是手动合并呢?

当Git不知道该保留两个修改中的哪一个时,就需要人来进行这个决策,可以选择保留两个修改中的任意一个,或是选择将两个修改全部保留。完成上述决策就是手动合并的目的。

问题3:为什么需要手动合并?

当可以自动合并时,说明两个人的修改不会冲突,但是当两个人对同一文件的同一区域进行了修改那么这两个修改就会产生冲突,Git将无法整合这两个修改,因为Git不知道它该保留两个修改中的哪一个(或是要一并保存),这是就需要人工进行手动合并了。

(3)、合并过后,就可以上传(git push)到远程仓库自己的分支

5.审核阶段

  • 管理员审核代码,没有发现问题后就可以将其与主分支进行merge,管理员应尽快完成这个过程,从而确保成员拉取到的都是最新版本。
  • 管理员合并过程中可能也会发生冲突,需要管理员联系成员了解情况后进行手动合并。
  • 管理员的作用:

维护远程仓库的master分支,包括以下:

  • 检查各个成员分支的代码有无问题
  • 将成员分支的代码合并到master分支
  • 合并发生冲突时,进行手动合并

6.冲突解决

1.冲突的类型

逻辑冲突

git自动处理(合并/应用补丁)成功,但是逻辑上是有问题的。

比如另外一个人修改了文件名,但我还使用老的文件名,这种情况下自动处理是能成功的,但实际上是有问题的。

又比如,函数返回值含义变化,但我还使用老的含义,这种情况自动处理成功,但可能隐藏着重大BUG.

这种问题,主要通过自动化测试来保障。所以最好是能够写出比较完备的自动化测试用例。

这种冲突的解决,就是做一次BUG修正。不是真正解决git报告的冲突。

内容冲突

两个用户修改了同一个文件的同一块区域,git会报告内容冲突。我们常见的都是这种,后面的解决办法也主要针对这种冲突。

树冲突

文件名修改造成的冲突,称为树冲突。 比如,a用户把文件改名为a.c,b用户把同一个文件改名为b.c,那么b将这两个commit合并时,会产生冲突。 如果最终确定用b.c,那么解决办法如下:

1
2
3
4
5
git rm a.c
git rm origin-name.c
git add b.c
git commit
复制代码

执行前面两个git rm时,会告警“file-name : needs merge”,可以不必理会。

合并时使用git rebase 和 git merge的区别

1339683149_4793.jpg

merge 操作遇到冲突的时候,当前merge不能继续进行下去。手动修改冲突内容后,add 修改,commit 就可以了。 而rebase 操作的话,会中断rebase,同时会提示去解决冲突。 解决冲突后,将修改add后执行git rebase –continue继续操作,或者git rebase –skip忽略冲突

2.变基(rebase)

变基要在自己本地仓库中拉出来的分支使用,不要对本地仓库外有副本的分支执行变基

git pull 与 git pull –rebase

  • git pull = git fetch + git merge
  • git pull –rebase = git fetch + git rebase

git pull –rebase,这里表示把你的本地当前分支里的每个提交(commit)取消掉,并且把它们临时 保存为补丁(patch)(这些补丁放到”.git/rebase”目录中),然后把本地当前分支更新 为最新的”origin”分支,最后把保存的这些补丁应用到本地当前分支上

冲突1

当你commit以后,在执行git pull –rebase的时候出现冲突,请按如下步骤解决:

  • 1 先找到冲突文件,解决冲突
  • 2 执行git add xxx(xxx为冲突文件全路径)
  • 3 执行git rebase –continue(合并冲突)
  • 4 执行git pull –rebase
  • 5 执行git push

冲突2

当你本地有修改的时候,你执行了git stash,然后又从服务器上pull了最新代码(git pull –rebase),出现了冲突,请按如下方式解决:

  • 1 找到冲突文件,解决冲突
  • 2 执行git add xxx(xxx为冲突文件全路径)
  • 3 git commit
  • 4 git pull –rebase
  • 5 git push

多人基于同一个远程分支开发的时候,如果想要顺利 push 又不自动生成 merge commit,建议在每次提交都按照如下顺序操作:

1
2
3
4
5
6
7
//git stash 能够将所有未提交的修改(工作区和暂存区)保存至堆栈中,用于后续恢复当前工作目录。
git stash
git pull --rebase
git push
//git stash pop 从Git栈中读取最近一次保存的内容,恢复工作区的相关内容。由于可能存在多个Stash的内容,所以用栈来管理,pop会从最近的一个stash中读取内容并恢复。将暂存文件取出,与pull的文件对比
git stash pop
复制代码

3.回滚(reset与revert)

git reset(重置)

git reset –hard 和 git reset –soft区别

  • git reset –-soft:回退到某个版本,只回退了commit的信息,不会恢复到index file一级。如果还要提交,直接commit即可;
  • git reset -–hard:彻底回退到某个版本,本地的源码也会变为上一个版本的内容,撤销的commit中所包含的更改被冲掉;

其中:AB 是正常提交,而CD是错误提交。现在,我们想把CD 回退掉。而此时,HEAD指针指向 D提交(5lk4er)。我们只需将 HEAD指针移动到B 提交(a0fvf8),就可以达到目的。

那么命令是什么呢?那就是git reset命令

1
2
git reset --hard a0fvf8 
复制代码

命令运行之后,HEAD指针就会移动到B提交下

image.png而这个时候,远程仓库的 HEAD指针依然不变,仍在 D提交上。所以,如果直接使用git push 命令的话,将无法将更改推到远程仓库。此时,只能使用-f 选项将提交强制推到远程仓库

1
2
git push -f 
复制代码

采用这种方式回退代码的弊端显而易见,那就是会使HEAD 指针往回移动,从而会失去之后的提交信息。将来如果突然发现,CD 是多么绝妙的想法,可它们已经早就消失在历史的长河里了。

git revert(撤销)

git revert的作用通过反做创建一个新的版本,这个版本的内容与我们要回退到的目标版本一样,但是HEAD指针是指向这个新生成的版本,而不是目标版本。

使用 git revert 命令来实现上述例子的话,我们可以这样做:先 revert D,再 revert C (有多个提交需要回退的话需要由新到旧进行 revert):

1
2
3
4
5
// 1 revert D
git revert 5lk4er
// 2 revert C
git revert 76sdeb
复制代码

那么就会生成两个新的提交:D'C'image.png这里只有两个提交需要 revert,我们可以一个个回退。但如果有几十个呢?一个个回退肯定效率太低而且容易出错。我们可以使用以下方法进行批量回退:

1
2
git revert OLDER_COMMIT^..NEWER_COMMIT
复制代码

这时,错误的提交 CD 依然保留,将来进行甩锅的时候也有依可循。而且,这样操作的话HEAD指针是往后移动的,可以直接使用 git push 命令推送到远程仓库里。而这种做法,正是企业所鼓励的。

git指令练习网站

可以让我了解每个命令执行后发生了什么的网站(感兴趣的可以去玩一玩) Learn Git Branching,练习git命令的网站

网站页面显示image.png比如:练习一道题

image.png介绍git rebaseimage.png未执行 git rebase main
image.png执行 git rebase mainimage.png未执行 git rebase bugFix

image.png执行 git rebase bugFix

image.png)题目问题操作提示image.png)答题界面介绍image.png答案 通过输入命令我们可以观察到右边的树状图都会发生改变,可以让我们更好的理解git命令

image.png下面的大家可以根据答案去输入git命令去尝试,我就不一一为大家解答啦!有疑问可以在评论区留言!

1
2
3
4
5
6
7
8
9
10
11
12
13
//新建并切换到bugFix分支
git checkout -b bugFix
//提交一次
git commit
//切换到main分支
git checkout main
//提交一次
git commit
//再次切换到bugFix分支
git checkout bugFix
//rebase 到 main
git rebase main
复制代码

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2020-2022 Henry
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信