Git的学习与心得
Git的学习与使用
Git简介
很多人都知道,Linus在1991年创建了开源的Linux,从此,Linux系统不断发展,已经成为最大的服务器系统软件了。
Linus虽然创建了Linux,但Linux的壮大是靠全世界热心的志愿者参与的,这么多人在世界各地为Linux编写代码,那Linux的代码是如何管理的呢?
事实是,在2002年以前,世界各地的志愿者把源代码文件通过diff的方式发给Linus,然后由Linus本人通过手工方式合并代码!
你也许会想,为什么Linus不把Linux代码放到版本控制系统里呢?不是有CVS、SVN这些免费的版本控制系统吗?因为Linus坚定地反对CVS和SVN,这些集中式的版本控制系统不但速度慢,而且必须联网才能使用。有一些商用的版本控制系统,虽然比CVS、SVN好用,但那是付费的,和Linux的开源精神不符。
不过,到了2002年,Linux系统已经发展了十年了,代码库之大让Linus很难继续通过手工方式管理了,社区的弟兄们也对这种方式表达了强烈不满,于是Linus选择了一个商业的版本控制系统BitKeeper,BitKeeper的东家BitMover公司出于人道主义精神,授权Linux社区免费使用这个版本控制系统。
安定团结的大好局面在2005年就被打破了,原因是Linux社区牛人聚集,不免沾染了一些梁山好汉的江湖习气。开发Samba的Andrew试图破解BitKeeper的协议(这么干的其实也不只他一个),被BitMover公司发现了(监控工作做得不错!),于是BitMover公司怒了,要收回Linux社区的免费使用权。
Linus可以向BitMover公司道个歉,保证以后严格管教弟兄们,嗯,这是不可能的。实际情况是这样的:
Linus花了两周时间自己用C写了一个分布式版本控制系统,这就是Git!一个月之内,Linux系统的源码已经由Git管理了!牛是怎么定义的呢?大家可以体会一下。
Git迅速成为最流行的分布式版本控制系统,尤其是2008年,GitHub网站上线了,它为开源项目免费提供Git存储,无数开源项目开始迁移至GitHub,包括jQuery,PHP,Ruby等等。
历史就是这么偶然,如果不是当年BitMover公司威胁Linux社区,可能现在我们就没有免费而超级好用的Git了。
Git的安装
Git安装可以参考文档https://www.liaoxuefeng.com/wiki/896043488029600/896067074338496
下载好git之后,我们就可以通过命令来查看git的版本
git --version
Git的初始化
当我们首次使用Git的时候,需要设置我们的名字和Email地址。表明我们的身份,当我们参与团队合作项目的时候,别人也可以通过我们的名字和Email与我们联系。
git config --global user.name "Your name" //设置你的名字
git config --global user.email "Your email address" //设置你的邮箱
然你你可以使用如下命令来查看
git config user.name
git config user.email
Git本地库示意图
场景一:Git本地版本库的基本用法
Git本地版本库
WorkSpace:就是你的本地工作区啦
Stage:待提交区(暂存区)
Local Repo:本地仓库
在本地仓库,我们首先在工作区修改,然后提交到暂存区,最后提交到本地版本库。大体的命令代码如下
Git本地仓库创建
Git创建版本库有两种方法。第一种是在本地创建版本库,或者是clone远端的版本库从而在本地建立一个版本库
git init # 在本地建立一个版本库
git clone https://github.com/YOUR_NAME/REPO_NAME.git # 通过clone远端的版本库从而在本地创建一个版本库
这里我们先讲解本地创建版本库,我们使用VSCode来做演示,我们先建立了一个Test文件夹作为演示的文件夹
在建立版本库的时候,可以直接使用VSCode自带的工具建立本地版本库,也可以使用命令行来建立。
- 使用VSCode
- 使用命令行
git init
这样我们就成功的建立了一个本地仓库
Git仓库状态的查看
要随时掌握工作区的状态,使用git status
命令。
如果git status告诉你有文件被修改过,用git diff
可以查看修改内容。
git status 是我们最最常用的命令,要学会看这个命令带给我们的提示。然后要学会使用 git diff。
git status # 查看工作区状态
git diff # 查看修改内容
我们执行一下git status命令
可以看到,由于刚刚创建仓库,我们没有任何的提交
下面试一下Git diff,查看工作区和暂存区的不同,创建一个Test.txt文件,并输入
Hello World
提交到暂存区(命令稍后说明) git add Test.txt
本地修改,在Test.txt加入 Hello Java
Hello World
Hello Java
调用命令git diff
可以看到改变
如果想查看某个具体的文件
git log <filename>
也可以根据具体版本号比较文件
git diff [本地库中历史版本] [文件名]
向Git仓库添加文件
首先我们编写一个README.md文件
- 第一步,使用命令添加到暂存区
git add <filename> ## 添加filename文件到暂存区
git add . ## 将工作区所有修改的文件加入暂存区
我们将README.md添加到暂存区
git add READMD.md
似乎没有任何提示,说明添加成功
- 第二步,将暂存区文件添加到本地仓库
git commit <filename> -m "message" ## 添加filename文件到仓库
git commit -m "message" ## 将暂存区有修改的文件加入仓库
添加成功后会有提示
Git版本回退
- git日志
首先我们必须要知道我们提交了几次,可以通过查看git日志的方法来查看
git log
可以发现我们有三次提交,需要注意的是,看到一串黄色的字符串是代表commit_id(版本号),使用Hash计算
- 回退版本,现在我们想要回退到上一个版本
首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD
表示当前版本,也就是最新的提交9598409...
(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD^
,上上一个版本就是HEAD^^
,当然往上100个版本写100个^
比较容易数不过来,所以写成HEAD~100
。
现在,想要回到上一个版本,我们可以使用如下的命令
git reset --hard HEAD^
git reset --hard HEAD~1
git reset --hard Hash值
就被还原了
--hard 参数
+ 在本地库移动 HEAD 指针
+ 重置暂存区
+ 重置工作区
reset 其他参数解释
--soft 参数 仅仅在本地库移动 HEAD 指针
--mixed 参数 ① 在本地库移动 HEAD 指针 ② 重置暂存区
现在让我们看看git log
只有两次的记录了,我们想回到最新的版本怎么办?
如果你还记得上面的最新版本的Hash值9598409...
,可以使用git reset --hard 9598409...
回去,但是如果你第二天起来想回到最新版本怎么办,忘记了哈希值。不要急,也有办法
git reflog
可以查看当前HEAD之后的版本
即我们可以查看2之后的3这个版本
最上面那行代表我们现在HEAD位置,下面三行的第二行即HEAD,那个9598490
即我们未来的版本,知道了版本号我们使用
git reset --hard 9598490
回去就行
管理修改,撤销修改,删除修改
- 管理修改
在一个阳光明媚的早晨,你决定使用git进行版本控制管理
你首先在OMG.txt
写下了
Hello
你添加了它,git add OMG.txt
,
你又修改了这个文件
Hello
Oh my god,Trump tested positive for COVID-19
并且你使用git commit -m "This is a interesting thing"
提交到了版本库
你会发现第二次修改没有经过暂存区就提交了
我们回顾一下操作过程:
第一次修改 -> git add
-> 第二次修改 -> git commit
Git管理的是修改,当你用git add
命令后,在工作区的第一次修改被放入暂存区,准备提交,但是,在工作区的第二次修改并没有放入暂存区,所以,git commit
只负责把暂存区的修改提交了,也就是第一次的修改被提交了,第二次的修改不会被提交。
小插曲:如果使用git commit -a -m "Message"
则跳过工作区到暂存区步骤直接进入仓库,
或者直接指定文件名git commit <filename> -m "Message"
- 撤销修改
自然你是不会犯错误的,只会有小小的失误,某天你加班到了凌晨两点
你写下了
Trump is stupid
你意识到了这句话的不妥,于是你想纠正他
现在你还没提交文件到暂存区
我们可以查看一下git status
你可以选择①手动删除这行话②使用git restore <文件>
来丢弃工作区的改动,现在撤销修改就回到了和版本库一样的状态
PS:①选择手动修改比较好,万一你的其他修改也没了呢②git checkout -- <filename>
也是可以的
现在你把文件提交到了暂存区
你同样需要查看一下git status
按照它的提示进行,就能将文件从暂存区回到工作区,按照上面方法修改git restore --staged OMG.txt
如果你把文件提交到了版本库
没有问题,使用版本回退就可以了。但是如果你提交自己的版本到了远程版本库,那就。。真的很难修改了(提交一个新的版本)
- 删除文件
我把刚才建的Test.txt
在本地删除了
查看git status
如果要删除的话就git add <filename> or git rm <filename>
添加到暂存区然后使用git commit
来确认删除
否则就使用git restore <filename>
来恢复文件把。
如果已经添加到暂存区了,就先把文件从暂存区撤回工作区,git restore --staged <filename>
然后恢复
如果添加到了暂存区并且git commit
提交了怎么回退?
版本回退
场景二:Git远程版本库的基本使用
创建一个新的远程库
首先我们去GitHub创建一个新的仓库
现在,远程库已经准备好了,我们把它clone下来
git clone https://github.com/XXX/XXX.git
当然这是我自己的,不过克隆下来是一个空仓库,克隆下来默认远程库的别名叫做orign
现在我们可以使用命令查看当前远程库别名了
git remote # 查看当前远程库地址别名
git remote -v # 查看当前所有远程地址别名
这时候我们就可以在本地仓库进行修改,删除等一系列操作了,我们添加一个README.md
然后把本地仓库推送到远程库
不要忘记先要添加到本地的暂存区->本地仓库,然后推送到远程库git add
,git commit
推送到远程库可以使用命令
git push [远程别名(默认是orign)] [当前分支名(默认是master)]
在推送过程中会要求输入GitHub账号密码,根据提示来就可以,这里不再展示,下面是推送完效果
如果想要下载远程库的最新代码,只需要使用命令
git pull
就会下载最新的代码
另外,讲解一些fetch和merge和pull
关联已有的本地仓库
如果我们已经有了一个本地仓库,想推送到远程仓库怎么办呢,我们首先在远程创建一个仓库,创建的仓库名最好和本地仓库相同,然后我们可以使用命令
git remote add [别名] [远程地址]
来和远程仓库关联
这里不用先Clone,可以直接到本地目录下输入指令
git remote add orign https://github.com/XXX/XXX.git
然后使用git push orign master
就成功推送过去了
小总结
如果本地已有仓库,就使用git remote add
来将本地仓库推送到远程同步
如果本地没有仓库,新建了一个远程仓库,可以使用git clone <远程地址>
来创建本地仓库并和远程仓库同步
上面步骤完成后,使用git push
来推送,可以使用git pull
来接收最新的远程版本库
场景三:团队项目中的分叉合并
在项目中,我们每个人开发都拥有自己的分支,然后在自己的分支上进行对代码的添加修改。
每个人在自己的分支上进行对代码的操作,最后合并到主分支上
- 首先,我们需要克隆或者同步最新的代码库到自己的电脑上
git clone https://DOMAIN_NAME/YOUR_NAME/REPO_NAME.git
git pull
- 我们需要创建一个分支,并且在这个分支上操作
git branch <分支名> # 创建分支
git branch # 查看分支
git branch -v # 查看更详细的分支信息
- 我们切换到自己的分支进行操作
git checkout <分支名>
- 最后我们需要合并分支
第一步:切换到接受修改的分支(被合并,增加新内容)上 git checkout [被合并分支名]
第二步:执行 merge 命令 git merge [有新内容分支名]
这里我们执行在mster上合并mybranch1分支指令
git checkout master # 切换到主分支上
git merge mybranch1 # 合并分支
如果我们想要体现自己的时间线,而不是master分支的时间线,我们需要执行如下指令git merge --no-ff mybranch1
结果如下
可以看到体现了我们自己的时间线
- 分支的解决冲突
有时候我们的分支和master冲突了,比如你在分支的README.md修改了一段,而maser被别人修改了一段,恰恰修改了同一部分,这时候就需要手动解决冲突了。
①这里我的master的README.md有如下部分
Hello World
edit by master
②而mybranch1的README.md有如下部分
Hello World
edit by master
合并分支的时候就会产生冲突
这时候我们的README.md会标示出冲突的部分
我们需要手动修改,修改到满意为止
然后调用git add .
和git commit -m "Message"
来提交
冲突解决了
冲突的解决
第一步:编辑文件,删除特殊符号
第二步:把文件修改到满意的程度,保存退出
第三步:git add [文件名]
第四步:git commit -m "日志信息"
注意:此时 commit 一定不能带具体文件名
场景四:Git Rebase
在上一个场景我们看到了,我们先在自己的分支上进行开发,然后合并到主分支上,如果我们在自己的分支上进行提交,如下图
合并完成之后我们会发现版本图是这样的
太不合理了,我们命名可以把A->B->C合成一个到我们的master上。
这就需要用到命令
git rebase -i (id 号码的父亲)
指的是以哪个版本作为奠基,合并其他版本,合并完后只留下奠基的版本
我们先建立自己的分支,然后分别提交三次版本ABC
接着我们准备把这三次版本奠基,只留下A版本,合并B和C版本,输入git rebase -i HEAD^^^
跳出这个界面
可以看到下面提示有变基的不同方法,我们使用s,融合到前一个提交
保存退出,退出后如果有冲突的话,我们需要根据提示处理冲突
解决完毕冲突后运行
git rebase --continue
不要忘记上面的步骤完了使用git add
和git commit
提交到版本库呦
再使用git log
查看
只剩下了A版本,然后和主版本合并就可以了
另外,在变基过程中,随时可以用以下命令终止
git rebase --abort
场景五:Fork + Pull request
前面的场景三四都是基于大家是同一个开发团队,现在,如果你不是团队的人,但是像为开源项目增加代码或者修改bug,你应该怎么做呢?
就需要使用
Fork+ Pull request的协作开发工作流程。
- 先 fork(分叉) 别人的仓库,相当于拷贝一份;
- 做一些 bug fix或其他的代码贡献;
- 发起 Pull request 给原仓库;
- 原仓库的所有者 review Pull request,如果没有问题的话,就会 merge Pull request 到原仓库中。
我们首先进入别人的版本库点击fork
按钮,然后回到自己的地方对其进行修改
修改完了以后我们可以点击Pull requests进行提交,然后
最后合并代码
这篇文章的写成参考了大量的资料
1.https://mp.weixin.qq.com/s/Km5KuXPETvG0wCGHrvj9Vg
2.http://www.ruanyifeng.com/blog/2014/06/git_remote.html
3.https://www.yuque.com/liweiwei1419/yby7qi/ocpind
4.https://blog.csdn.net/weixin_33127753/article/details/88870257
其他命令
git revert
revert 的含义
revert 能做的事情:revert 可以取消一个 commit。
如果我们很好地能够做到一个 commit 做一件事情,以后想要取消的时候,就会变得非常容易。
revert 还有一个使用场景:
刚刚 push 的时候,如果反悔了,可以使用一个 revert 的操作去撤销它。
git blame <filename>
# 显示指定文件是什么人在什么时间修改过
-
git log
补充git log --pretty=oneline
简洁方式显示git log
另外,如果git log过多,可以显示
(1)git log --graph
(以图表形式查看分支)
显示字符界面的提交关系图,不同的分支使用不同的颜色来表示。
小技巧:可以使用 git config --global alias.glog “log
--graph” 起一个别名。
然后以后再使用的时候,就可以用 git glog。
(2)git log --stat
说明:--stat 表示查看每次提交文件变更的统计。这条命令可以帮助我们查看每一次提交具体的文件变化。
(3)git log -l --pretty=raw
我们会看到 SHA1 哈希值。--pretty=raw 显示每个提交对象的 parent 属性。
暂时没有发现有什么不同的地方。
(4)git log --pretty=oneline
更常用的一种写法是:
(5)git log --graph --oneline
(6)git log -5 --pretty --oneline
显示过去五次提交
(7)git log -p [file]
显示指定文件相关每一次diff
另外,如果git log
一页显示不了
b->向上翻页
空格->向下翻页
q->退出