自己之前写过两篇关于Git和GItHub使用的文章,分别是
浅谈使用git 进行版本控制博客链接:https://www.cnblogs.com/wj-1314/p/7992543.html
使用GitHub的点点滴滴的博客链接:https://www.cnblogs.com/wj-1314/p/9901763.html
说真的,学一遍,记录一遍,都有不同的感悟,第一次学习Git的时候,也就是2017年12月,觉得这个东西很神奇,当时还是一个学生,只是看别人都在学,自己也学一下,但是却没有深入使用,只是知道一些原理和拉代码等;第二次学习Git上传代码到GitHub上传代码的时候总是遇到一些问题,就是2018年11月。有句话说的好“好记性不如烂笔头”,所以将自己使用Git进行拉取和上传代码到GitHub的流程和遇到问题记录下来,所以就有了第二篇文章,记录自己使用GitHub的点点滴滴,而现在已经是2023年2月份了,距离第一次学习Git已经五年了,自己也早已经会其操作了,但是女盆友不太会,所以写一篇笔记帮一下她,也是自己对git的理解做一个总结。
首先说明一下Git和GitHub是两个完全不同的概念。
1,Git与GitHub的区别
GIT是一个开源的分布式版本控制软件,用以有效高速的处理从很小到非常大的项目版本管理。简单说就是一个版本管理工具,是可以在电脑不联网的情况下只在本地使用的版本管理工具,其作用就是可以让我们更好的管理代码,进行版本控制。
安装Git,请参考博客:GIT安装教程(windows)
而GitHub是一个基于Git的远程文件托管平台(同GitCafe BitBucket和GitLab等),简单说是一个网站,比如说程序员将自己代码存储在GitHub的一个仓库中,别人可以看到,也可以协同操作,方便程序员之间互相学习和交流。
2,Git的工作原理
2.1 正常的提交版本
Git把管理的文件分为了两个区域四个状态,如下图:
工作区
当前开发程序所在的目录称为工作区,即:工作开发都是在该目录,该区域的文件会有状态的变化且状态由git自动检测,如果程序中文件做任何操作(增,删,改),文件状态均会被检测到,可以使用下面命令查看:
git status
工作区通俗的说就是我们写代码的区域,比如在vscode的IDE上开发代码,其项目文件夹就是工作区。
版本库
工作区检测到有文件发生变化,那么意味着较上一个版本之后对程序进行了修改,修改完成之后,可以当做下一版本进行提交,那么就是执行下面命令:
git add .
此命令将所有文件提交到暂存区,然后执行下一个命令:
git commit -m "下一个版本"
此命令可以提交到版本库的分支,之后可以使用下面命令查看版本记录
git log
使用的命令记录:
目前已使用Git的四个命令,这四个命令已经可以代替本地多个文件保存版本的方式: git init,初始化,表示即将对当前文件夹进行版本控制。 git status,查看Git当前状态,如:那些文件被修改过、那些文件还未提交到版本库等。 git add 文件名,将指定文件添加到版本库的暂存状态。 git commit -m '提交信息',将暂存区的文件提交到版本库的分支。 git log,查看提交记录,即:历史版本记录
如果是远程的代码,或者说团队协作开发的代码,可能需要push到主分支上,等待项目的owner进行merge。如果项目的owner发现你提交的代码有问题,或者不符合预期,需要你进行修改,就需要回滚操作了。
所以当之前保存的代码发生问题,那么如何回滚呢?
2.2 回滚到之前的版本
首先,使用下面代码,查看历史版本记录:
git log
一般会出现下面几个关键的东西:
commit 0972f4bb43104baee15aeec2dd62bd0a312ds123 Author: james Date: Fri Aug 11 10:54:42 2018 +0800 Monday update 11.7 commit 0972f4bb43104baee15aeec2dd62bd0a378de456 Author: james Date: Fri Aug 11 10:54:42 2018 +0800 Tuseday update 11.8
你可以使用下面代码回滚到指定的版本:
git reset --hard 0972f4bb43104baee15aeec2dd62bd0a378de456 HEAD is now at 6c439d2 Tuesday update 11.8
hard是强制回滚,表示回退删除,因为是不可逆操作,所以确保自己本地代码不需要了,才可以回退删除。
soft 回退,如果有差异则存在暂存区,不会轻易删除代码。
回滚完成了,如果某天,想回到之后的高级版本,如何做呢?(为啥这么多如果呢,其实就是自己回滚后,发现误删了别人的东西,又需要返回去,在项目开发中也是比较常见的失误)
2.3 从之前回滚到之后的版本
首先,使用下面代码,查看记录(下面代码:查看命令历史,挽回错误的重置,用来记录我们的每一次命令)
git reflog
会查看到下面内容:
6c439d2 HEAD@{2}: reset: moving to 0972f4bb43104baee15aeec2dd62bd0a378de456 0972f4b HEAD@{3}: commit: Monday update 11.7 6c439d2 HEAD@{4}: commit (initial): Tuesday update 11.8
使用下面代码即可back的之后的版本:
git reset --hard 0972f4b
结果如下:
HEAD is now at 0972f4b monday 11.7
3,利用Git + GitHub进行团队协作开发
团队协作开发中,大部分使用到版本控制软件,也许代码存储的地方不一样,但是原理不尽相同。所以这里以Git+GitHub为例详细聊一下在真实的工作环境中如何协作开发。
3.1 分支类型介绍
每个仓库中可以包含多个分支,每个分支都对应一个独享的目录,各个分支并列在仓库下面。不过常规的是以master分支为主,还有dev分支。
master分支:即主分支,任何项目都必须有这个分支,一般都是项目的leader或算法的架构拥有操作权。通过主分支可以对项目进行tag或者发布版本等操作。
develop分支:即开发分支,这个分支从master分支上检出。而团队开发成员一般不会直接更改这个分支,这个分支的owner也是算法架构。一般来说团队开发成员会从该分支检出自己的feature分支,开发完成后将feature分支上的改动进行pull request,由项目的owner进行代码check,如果没问题则会merge到develop分支。同时release分支由此分支检出。
release分支:即发布分支,从develop分支上检出。该分支用作发版前的测试,可进行简单的bug修复,如果bug比较大,则可merge回develop分支上,由开发成员进行bug修复再提交代码。此分支测试完成后,需要同时merge到master和develop分支上。
feature分支:即功能分支,从develop分支上检出。团队成员每个人都维护一个自己的feature分支,并进行开发工作。开发完成后提交代码,由项目owner检查,再merge回develop分支。此分支一般由开发人员开发新功能或进行项目维护等。
总结:如果只是开发人员,只需要关注自己的feature分支,完成代码后提交dev分支即可,其他分支做了解即可(其实还有hotfix分支,因为本人并未使用过,就不误导大家了)。
3.2 团队协作开发项目流程
假设团队中需要做一个新的项目,并且计划将代码托管到GitHub上。那么首先就需要项目的owner在Github上创建一个新的项目,暂且称为 Project_1。同时他将其关联到GitHub上的origin/master上,假设这个项目的基础版已经完成,则owner会在master分支上打tag,假设命名为V0.1,此时V0.1的项目已经正常运行了。
但是PM提出了新的需求了,所以项目owner需要分配团队成员开发功能,那么他负责在master分支上新建并检出dev分支,新开发的功能肯定在dev分支上进行。
# 从master分支上新建develop分支 git branch develop master # 检出develop分支 git checkout develop
目前dev分支创建完成了,并且团队的十个开发成员也开完会了,每个人都有开发任务,并且开发不同的功能,这时候项目的owner会告诉开发成员,团队的每个人都需要从代码仓库中克隆项目,然后在dev下创建自己的feature分支了。
下面为其clone流程:
# step1 clone 仓库 git clone xxxx.git # step2 检出develop分支 git checkout develop # step 3 从develop分支新建并检出feature分支 git checkout -b feature-xx develop
经过了一段时间。。。。。
目前程序员A已经完成了自己的需求了,并且提交了代码。其流程如下:
# step1 可以检测一下自己当前的分支,方便复制自己的feature名称 git branch -a # step2 提交代码之前,需要检测一下dev仓库是否有其他同事提交了代码 # 情况1:如果其他同事没有提交代码,直接pull git pull origin develop # 情况2: 如果其他同事提交了代码,这里可以先暂存自己的代码,然后拉取新代码 git stash git pull origin develop git stash pop # step3,开始上传自己需要上传的代码 git add . git commit -s -m "my code" git push origin feature_xx
此时 自己的代码已经上传到自己Github的远程仓库了,这也是做一个备份,同时提交pull request需求,将代码提交到dev分支上,等待算法owner进行merge。
注意:在团队合作时,commit message的书写格式应该遵守相应规范,清晰明了的commit message有助于快速定位提交,自动生成change log文档。
这时候存在两种情况,一种是代码符合要求,算法owner直接merge代码;一种是代码存在bug,需要继续修改,这样自己需要继续修改。
假设程序员同学完成了自己bug修复,修改完成后再提交代码。注意这里不需要再commit新的信息了,为了避免提交无用信息,这时候可以使用git amend。
# 完成代码后,检查操作同上,这里不再赘述,然后提交代码 git add . git commit --amend git push origin feature_xx
amend的好处就是提交日志只存在一次提交记录,信息也是显示的是我们第二次修改的信息,最终项目owner进行merge代码。开发完成。
这里通过Pull requests 简单说了一下团队开发的流程,当然也可以使用GitFlow工作流的方式,主要看自己团队和具体业务的协作方式是什么。当然Git博大精深,我也只是勉强用着。
3.3 git branch 和git checkout
之前说到了新建分支,检出等概念,这里详细介绍一下,也给自己留个笔记。常用命令如下:
git branch //查看当前分支 git branch -r //列出远程分支 git branch -a //列出所有分支 git branch branchName //创建分支 git checkout branchName //切换分支 git checkout -b branchName //创建并切换到分支 git checkout //后面不跟任何参数,则就是对工作区进行检查 git checkout --filename //从暂存区中恢复文件(确保filename与branch名称不同) git status //查看状态
这里解释一下 git checkout -b BRANCH_NAME,意思是创建一个新的分支,并且切换到这个新的分支。为什么说这个呢?因为常用是一方面,另一方面是这个命令其实是执行了以下两个操作:
# 创建一个新分支 git branch BRANCH_NAME # 然后把分支从当前分支切换到新分支 git checkout BRANCH_NAME
因为git branch BRANCH_NAME虽然创建了新的分支,但是仍然将我们留在了同一分支。适用情况如下:项目的leader为了方便管理feature分支,他在dev分支下同时给所有开发人员创建了新的分支,命名统一管理,所以需要使用这个命令。
3.4 Git push
为什么要说一下push,因为大部分人熟练后都会使用缩写或者简写,这里将push再做一个笔记,方便新手入门。
在使用 git commit 命令将修改从暂存区提交到本地版本库后,只剩下最后一步将本地版本库的分支推送到远程服务器上对应的分支了,而推送使用的命令为git push,下面详细学习一下。
git push 的一般形式为:
git push
举个例子: git push origin master:refs/for/master ,即是将本地的master分支(本地叫什么都无所谓,自己认识就可以)推送到远程主机origin上的对应master分支, origin 是远程主机名,第一个master是本地分支名,第二个master是远程分支名。
1, git push origin master
这个是大家常用的命令,其意义是如果远程分支被省略,如上表示将本地分支推送到与之存在追踪关系的远程分支(通常两者同名),如果该远程分支不存在,则会被新建。
2, git push origin : refs/for/master
如果省略本地分支名,则表示删除指定的远程分支,因为这等同于推送一个空的本地分支到远程分支,等同于 git push origin — delete master
关于 refs/for:
//refs/for 的意义在于我们提交代码到服务器之后是需要经过 code review之后才能进行 merge的,而 refs/heads 不需要
3,git push origin
如果当前分支与远程分支存在追踪关系,则本地分支和远程分支都可以省略,将当前分支推送到 origin 主机的对应分支
4,git push
如果当前分支只有一个远程分支,那么主机名都可以省略,可以使用 git branch -r,查看远程的分支名
5,git push -u origin master
如果当前分支与多个主机存在追踪关系,则可以使用 -u 参数指定一个默认主机,这样后面就可以不加任何参数使用 git push,注意不带任何参数的 git push,默认只推送当前分支,这叫做 simple方式,还有一种 matching 方式,会推送所有有对应的远程分支的本地分支,Git 2.0 之前默认使用 matching,现在改为 simple方式,如果想要更改设置,可以使用 git config命令。
git config --global push.default matching git config --global push.default simple 可以使用git config -l 查看配置
6,git push –all orgin
当遇到这种情况就是不管是否存在对应的远程分支,将本地的所有分支都推送到远程主机,这时需要 –all 选项
7,git push –force origin
git push 的时候需要本地先 git pull 更新到跟服务器版本一致,如果本地版本库比远程服务器上的低,那么一般会提示你 git pull 更新,如果一定要提交,那么可以使用这个命令。
8,git pusj origin –tags //
git push 的时候不会推送分支,如果一定要推送标签的话,那么可以使用这个命令。
3.5 Git stash
上面提到了一个命令叫做git stash,这是啥意思呢? 他其实处于git reset –hard(完全放弃还修改了一半的代码)与git commit(提交代码)的命令之间,很类似于“暂停”按钮。
git stash 可以将本地的代码没有提交的代码存储起来。如果git stash之后,再使用git status查看本地工作区的状态,我们会发现所有没有commit的代码,都会暂时从工作区移除,回到上次commit的状态,并且非常干净,如果需要取出之前储藏的代码,使用 git stash pop即可。
如果做了多次储藏,则需要使用git stash list查看其记录。
# 列出所有暂时保存的工作 $ git stash list stash@{0}: WIP on workbranch: 56cd5d4 Revert "update old files" stash@{1}: WIP on project1: 1dd87ea commit "fix typos and grammar" # 恢复某个暂时保存的工作 $ git stash apply stash@{1} # 恢复最近一次stash的文件 $ git stash pop # 丢弃最近一次stash的文件 $ git stash drop # 删除所有的stash $ git stash clear
上面命令再解释一下,git stash pop命令总是取出最近一次的修改,但是可以使用git stash apply指定取出某一次的修改。而git stash apply不会自动删除取出的修改,需要手动删除,git stash drop stash@{1}。
git stash 子命令常见的用法:
git stash: 备份当前的工作区的内容,从最近的一次提交中读取相关内容,让工作区保证和上次提交的内容一致。同时,将当前的工作区内容保存到Git栈中。 git stash pop: 从Git栈中读取最近一次保存的内容,恢复工作区的相关内容。由于可能存在多个Stash的内容,所以用栈来管理,pop会从最近的一个stash中读取内容并恢复。 git stash list: 显示Git栈内的所有备份,可以利用这个列表来决定从那个地方恢复。 git stash clear: 清空Git栈。此时使用gitg等图形化工具会发现,原来stash的哪些节点都消失了。 git stash show -p :展示目前存在的stash git stash drop:丢弃最近一次stash的文件 git stash apply stash@{1}:恢复某个暂时保存的工作 git stash drop stash@{1} : 由于上面命令不会自动删除取出的修改,所以需要手动删除
git stash的应用场景就是:作为开发者使用自己的分支修改和调试代码,如果同事发现自己的分支上有一个不得不修改的bug,那么为了不影响自己的开发,并且让同事的bug不影响自己,那么需要将同事修改后的代码拉下来,这样使用git stash 就会将当前未提交到远程服务器的代码推入到自己的Git的栈中,这时候拉下同事的代码后,再把自己的代码取出来即可。