首先,在阅读下面的文字之前,我将假设你已经有了一定的Git基本指令的操作经验,在这些方面本文不多做理论性的说明。
如果在阅读文章之后,你想要要更深入的探索Git的世界,那么以下是作者认为较好的学习资料,真诚地推荐你进行详细阅读:
GitHub官方文档
Git教程-廖雪峰网站
正文部分的讲解将以作者认为功能为核心展开,同时附带一些开源协同的简单规范,具体如下:
-
项目克隆与创建 -
Git基础指令 -
分支管理与rebase -
冲突解决
一、项目克隆与创建
一个项目是否由Git管理,可以通过查看项目目录下是否有一个.git 文件来辨别。
怎么让我们的项目由Git来管理呢,一般有两种方式。
第一种,先在本地创建一个Git仓库。很简单,在终端cd到项目路径下,使用git init 指令,就会自动创建这个项目的本地版本库,如下:
现在,我们就有了一个本地的代码仓库,在这个仓库中的任何更改都会被Git记录并管理,但是,这个仓库目前还只存在在你的设备中,要将它与GitHub等管理平台联系上,还需要在你所选择的托管平台进行一些操作,但他们一般都有平台的使用指导,可以在图形化界面上Import一个本地仓库,简单完成,这里不做赘述:
第二种,先在GitHub上创建一个仓库repository,之后通过git clone 将它克隆至本地。
首先点击Code下拉按钮,之后点击出现的网址后边的复制按钮,回到本地的终端界面,cd到你想放置项目的路径,之后git clone link
就将项目同步克隆到本地了。
二、Git基础指令
首先,我们按向项目新增一个文件的流程走一遍。
这里,我已经创建了一个新文件Document.md,并把它直接存在了仓库下。我想直接把这个作为一次提交上传。
第一步:git status 查看工作区的状况:
可以看到,这里提示我们有一个未跟踪文件,Document.md就是我新添加的文件,然后,将它添加暂存区:
git add Document.md
再次git status ,查看信息:
这样的提示表示这个文件已经进入了暂存区,同时这次的更改被保存,现在你对这个文件做更改后都可以通过暂存区找回原来的版本。
接着,使用commit 指令提交这个暂存:
-m "xxxx" 引号中是对这次提交的描述。
这时,再次git status ,就能看到,本地已经领先远程1个提交了:
需要注意的是,在已有文件上的修改是会被Git跟踪的,而未跟踪文件一般是直接添加的文件,即并不在上一版本中,或是其文件格式不支持由Git管理其更改。
现在,我们已经知道了如何使用Git进行版本的管理,即使用add 和commit 进行代码的提交。
但是,我们现在所做的提交、更改都仍在本地,要想与远程进行同步,就需要使用另外的两条指令:pull 和push 。
git pull 指令表示拉取远程仓库的最新版本代码,默认拉取的分支是远程的主分支。
这里因为会引入冲突,我们转到第四节冲突管理时介绍
git push 指令表示上传本地的分支到远程仓库中,这里默认上传是从本地当前所在分支->远程主分支,如果想要更改上传的本地分支为其他,则只需要切换到相应的分支(使用git switch 指令,后接分支名称);另一方面,如果想将本地的分支上传至远程的非主分支,需要在push 后面指定远程的分支名,假设此时需要上传到远程分支dev ,则指令如下:
git push dev
如果指定的dev 分支并不存在,则会在远程自动创建,当然,在远程仓库平台如GitHub等都会在push 后生成响应,如果上传至非主分支,将需要上传者指定是否生成一个merge request 即是否将它合并至主分支。
三、分支管理与rebase
分支是Git中一个非常有魅力且灵活的功能,通过分支管理,项目的协同合作变得更加规范且安全。
每个项目都有一个主分支即master ,而在没有创建其他分支时,我们的每次提交都只是在主分支的时间线上往前迈步,这时,版本库相当于一根水平向前的时间轴,这样的脉络非常清晰,但在实际使用中,容错性能很低。假设在主分支上发生意外,那么就只能回退,而当多人协同时,如果每个人都直接向主分支提交代码,那每次一个人修改时就要兼顾之前其他人的全部修改,以防主分支代码出错,这样并行化效率就相当差了。
现在,我们已经阐述了分支的重要性,接下来,详细说明分支的工作原理。
一开始的时候,master 分支是一条线,Git用master 指向最新的提交,再用HEAD 指向master ,就能确定当前分支,以及当前分支的提交点:
这时,我们创建并切换到一个新的分支dev :
git checkout -b dev
这时,这个新的分支上没有任何提交,所以它其实与master 是一致的。
当我们commit 之后,dev 就领先master 一个提交了:
这样,就能理解Git是如何实现版本的回退等功能的了,它只需要将指向最新版本的指针转为指向前一个或者更久之前的版本号;而合并分支,就是将master 和dev 同时指向一个合并后的新的版本即可。
在看完上面的解释后,相信你对分支的原理也有了一定的了解,其实Git管理的项目版本库相当于一棵大树,其他的分支就是主干上分出的枝丫,而分支名则像一个指针,指向这个分支的最新版本。
master 指向主分支的最新版本,那么head 就指向我们当前所在的分支的最新版本。
rebase 指令,字面理解为变基。
我们每次commit 都会在Git中留下一个提交,而表现在版本树上,就是很多的分叉,这时,如果我们将多个提交的代码push 到远程,这些提交也会原封不动的上传,即远程的版本树一下也劈叉了,这个问题说大不大,说小也不小。
在需要回退版本的时候,我们往往需要查看版本树或git log 查看信息,获取版本号,如果过去的提交过多,分叉过复杂,在打印的版本树上就很难获取信息了,这就需要我们进行变基即rebase 操作。
使用git rebase 后,我们的整个提交历史就成了一条直线,rebase 操作前后,最终的提交内容是一致的,但是,我们本地的commit 修改内容已经变化了,它们的修改不再基于之前的数次提交,而是基于主分支的内容,但最后的提交内容是一致的。
接下来,罗列说明几个分支管理的重要指令:
-
git checkout -b <name> 创建并切换到新分支 注意,checkout指令本不用于分支创建,必须要?-b git checkout 查看分支是否与上游,master一致 -
git branch <name> 创建新分支 -
git switch <name> 切换到分支 -
git branch 查看分支 -
git merge dev 将dev 分支合并到master -
git rebase 将本地Git提交历史进行整理,成一条直线
四、冲突解决
在多人协作的场合,往往会出现这样的场景:你冥思苦想,薅了半把头发,终于把昨天的bug改好了,准备一键push ,却发现隔壁的小王早2个小时提交了一份,你没来得及pull 下来,而巧合的是,小王更改的部分正好与你改bug的部分重合了,两者冲突,push 失败了!
在这里,首先,我们需要明确的是,Git管理的不是项目文件本身,即它不记录一个文本的具体内容,如这个组件的背景色究竟是是white还是black,他只记录你提交到版本库的每个更改,并实施比对更改。所以,当我们理解Git的原理时,不要去想你的详细内容,而应这样去设想,这次提交更改了line 250,在line 166后新增了3行,删除了line100-150之间的行,诸如此类的操作都被Git记录为一个更改,且对这个更改进行定位。
现在,举例来说明冲突的形成。假设,我们有master 主分支和一个dev 分支,在创建了dev 分支后,在该分支上进行了一次提交,这样dev 就领先master 一个提交,之后,又在master 上修改并提交了,形象的描述就是,版本树产生了一个分叉,而这时,因为dev 分支上的任务已经完成并review无误,要将dev 合并(merge )入master 分支,如下图:
这时,合并会有两种情况:
-
两个分支上提交的更改没有撞车(更改的定位不重合) 可以直接合并,merge 直接成功 -
分支上存在更改同一处的冲突 发生冲突,无法合并
假设,此时是在把本地的分支合并到本地的master上,如果是在本地的IDE等编辑器中操作,那么,冲突一般会直接提示在文件中,并要求手动更改,确定一个版本,如下:
这里依赖编辑器的提示标注,产生冲突的文件在目录中会标红,但往往需要等待一会。
打开冲突文件,会以以下形式标注冲突,单书名号后跟的是分支名,head 为当前所在分支,这里就是master 。·
修改后,需要进行一次提交:
本地与远程的冲突就更为普遍了,也就是协同合作时易发生的问题。
事实上,解决冲突的方法有很多:
-
永远先pull 再push 意思是,永远保持本地与远程一致,直接在本地修改掉产生冲突的部分,当发生冲突时,先pull 最新的远程代码到本地,解决冲突后,再push 。 这里的pull 后冲突标注同上: 解决后再push 就成功了: -
提交到远程新分支,之后创建merge request 时解决 这个方法其实是将冲突保留了,让代码先上传到远程的非主分支,之后再合并主分支,这个方法的讨巧点在于,在GitHub等平台进行merge 时,会有更人性化的图形界面进行操作,更直观。 同时,在参与开源项目时,一般contributor没有merge 主分支的权限,就是说,将代码提交到远程分支后,会由社区的maintainer等管理者进行review,即查看代码是否可以被接受,并由这些人解决冲突。 当然,在一般的项目合作时,一般不设管理,成员都可以对main 分支直接修改,就可以采用中这个方式了。 首先,当分支提交到远程后,需要手动创建一个merge request,在merge request内,可以选择reviewer即向选择的成员发送邮件请求确认等等: 在创建了merge request之后,点击,查看是否可以直接合并,如果有冲突,则会提示: 可以选择在本地合并或者解决冲突Resolve conflicts,这里选中解决冲突,之后跳转到如下界面,依次选择合并使用的代码或进行修改: 确认后点击页面下方的Commit to source branch,即将修改提交到了当前的分支,然后回到merge request 页面。 此时Merge按钮变绿,点击合并。
如果可以,写一下review的comment,或在这里进行简短的沟通:
Tips:
一般编辑器如JetBrains全家桶和VSCode都可以下载Git插件,插件往往有图形化界面,在图形化界面进行的push和pull等操作往往会有弹窗进行操作,而在终端输入指令一般直接标注在项目文件内,在一些情况下活用插件可以大大方便操作~
笔者功底尚浅,如有问题,欢迎任何的批评指正与交流哦!🙏🏻
|