Git 教程
Git教程
Git简介
Git 是一种分布式版本控制系统,它可以不受网络连接的限制,加上其它众多优点,目前已经成为程序开发人员做项目版本管理时的首选,非开发人员也可以用 Git 来做自己的文档版本管理工具。
SVN与Git最主要的区别
SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以首先要从中央服务器哪里得到最新的版本,然后干活,干完后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,如果在局域网还可以,带宽够大,速度够快,如果在互联网下,如果网速慢的话,就纳闷了。
Git是分布式版本控制系统,那么它就没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上。既然每个人的电脑都有一个完整的版本库,那多个人如何协作呢?比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
工作原理 / 流程:
- Workspace:工作区(working directory)
- 就是你在电脑上看到的目录里的文件(.git隐藏目录版本库除外)
- Index / Stage:暂存区
- Repository:仓库区(或本地仓库/版本库)
- 工作区有一个隐藏目录.git,这个不属于工作区,这是版本库。其中版本库里面存了很多东西,其中最重要的就是stage(暂存区),还有Git为我们自动创建了第一个分支master,以及指向master的一个指针HEAD。
- Remote:远程仓库
HEAD
在掌握具体命令前,先理解下HEAD。
HEAD,它始终指向当前所处分支的最新的提交点。你所处的分支变化了,或者产生了新的提交点,HEAD就会跟着改变。
安装后需设置用户信息
第一次使用git的时候需要设置。因为Git是分布式版本控制系统,所以需要填写用户名和邮箱作为一个标识。
1 | 设置用户名: |
注:--global
参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然你也可以对某个仓库指定的不同的用户名和邮箱。
基础操作
1 | 初始化一个git仓库 |
版本回退
git reset --hard HEAD^
那么如果要回退到上上个版本只需把HEAD^ 改成 HEAD^^ 以此类推。那如果要回退到前100个版本的话,使用上面的方法肯定不方便,我们可以使用下面的简便命令操作:git reset --hard HEAD~100
即可
1 | 回退到上个版本(如果工作区有内容修改的话也会被覆盖,即该命令会将工作区变成和上个版本一模一样的代码,没提交的代码会丢失) |
现在我们已经还原到上个版本了,但是怎么变回去呢?
1 | 使用reflog查看还原前的版本号 |
Git撤销修改
在工作区已经修改了文件,但是希望恢复到以前的版本。
1 | 使用git checkout -- <fileName> 可以丢弃工作区的修改 |
上面的命令的作用是把readme.md文件在工作区做的修改全部撤销
这里有2种情况,如下:
- 1、readme.md自动修改后,还没有放到暂存区,使用撤销修改就会到和版本库一模一样的状态。
- 2、另外一种是readme.md已经放入暂存区了,接着又作了修改,撤销修改就回到添加暂存区后的状态。
远程仓库
1 | 添加远程仓库 |
创建与合并分支
1 | 创建并切换到指定的分支,保留所有的提交记录 |
解决冲突
Git用<<<<<<<
,=======
,>>>>>>>
标记出不同分支的内容,其中<<<<<<< HEAD
是指主分支修改的内容,>>>>>>> fenzhi1
是指fenzhi1上修改的内容
1 | <<<<<< HEAD |
手动解决冲突后,然后执行2个命令进行提交:git add .
&git commit -m "解决冲突"
1 | 以图片且单行的形式查看提交记录 |
分支管理策略
通常合并分支时,git一般使用"Fast forward"
模式,在这种模式下,删除分支后,会丢掉分支信息,现在我们来使用带参数–no-ff
来禁用"Fast forward"
模式。首先我们来做demo演示下:
1 | 创建并切换到新分支fenzhi2 |
可以看到被删除的分支的提交记录还存在。
分支策略:首先master主分支应该是非常稳定的,也就是用来发布新版本,一般情况下不允许在上面干活,干活一般情况下在新建的dev分支上干活,干完后,比如上要发布,或者说dev分支代码稳定后可以合并到主分支master上来。
bug分支(使用stash进行隐藏工作现场)
在开发中,会经常碰到bug问题,那么有了bug就需要修复,在Git中,分支是很强大的,每个bug都可以通过一个临时分支来修复,修复完成后,合并分支,然后将临时的分支删除掉。
比如我在开发中接到一个404 bug时候,我们可以创建一个404分支来修复它,但是,当前的dev分支上的工作还没有提交。比如如下:
1 | 当前工作区已经有修改了 |
并不是我不想提交,而是工作进行到一半时候,我们还无法提交,比如我这个分支dev要2天完成,但是我issue-404 bug需要5个小时内完成。怎么办呢?还好,Git还提供了一个stash
功能,可以把当前工作现场**”隐藏起来”**,等以后恢复现场后继续工作。如下:
1 | 将当前的工作现场隐藏起来 |
所以现在我可以通过创建issue-404
分支来修复bug了。
首先我们要确定在那个分支上修复bug,比如我现在是在主分支master上来修复的,现在我要在master分支上创建一个临时分支,演示如下:
1 | 如果要在master分支上创建分支,需要先切换到master分支 |
修复完成后,切换到master
分支上,并完成合并,最后删除issue-404
分支。演示如下:
1 | 切换回master分支 |
最后,我们回到dev分支上干活。
1 | 切回到dev分支 |
工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,可以使用如下2个方法:
- 1、
git stash apply
恢复,恢复后,stash内容并不删除,你需要使用命令git stash drop
来删除。 - 2、另一种方式是使用
git stash pop
,恢复的同时把stash内容也删除了。
演示如下:1
2
3
4查看stash列表内容
git stash list
恢复工作现场
git stash pop
多人协作
当你从远程库克隆时候,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且远程库的默认名称是origin。
- 1、要查看远程库的信息 使用
git remote
- 2、要查看远程库的详细信息 使用
git remote –v
1
2
3
4详细信息里包含有2条信息
git remote -v
origin https://github.com/Coding-Coder/testGit.git (fetch)
origin https://github.com/Coding-Coder/testGit.git (push)1. 推送(push)分支:
推送分支就是把该分支上所有本地提交到远程库中,推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上:
使用命令git push origin master
,如果我们现在要推送到其他分支,比如dev分支上,我们还是那个命令git push origin dev
2.抓取(fetch)分支:
多人协作时,大家都会往master分支上推送各自的修改。现在我们可以模拟另外一个同事,可以在另一台电脑上(注意要把SSH key添加到github上)或者同一台电脑上另外一个目录克隆,新建一个目录名字叫testGit2
但是我首先要把dev分支也要推送到远程去,如下
1 | git push origin dev |
接着进入testgit2目录,进行克隆远程的库到本地来,如下:
1 | git clone https://github.com/Coding-Coder/testGit.git |
现在我们的小伙伴要在dev分支上做开发,就必须把远程的origin的dev分支拉取到本地来,于是可以使用命令创建本地dev分支:
1 | 创建远程origin的dev分支到本地的dev分支 |
现在小伙伴们就可以在dev分支上做开发了,开发完成后把dev分支推送到远程库时。如下:
1 | 小伙伴在dev进行开发 |
小伙伴们已经向origin/dev
分支上推送了提交,而我在我的目录文件下也对同样的文件同个地方作了修改,也试图推送到远程库时,如下:
1 | 我在dev进行开发 |
根据git的提示,先用git pull把最新的提交从origin/dev抓下来,然后在本地合并,解决冲突,再推送
1 | git pull |
发现git pull也失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接:如下:
1 | 将本地的dev与远程origin/dev分支进行链接 |
因此:多人协作工作模式一般是这样的:首先,可以试图用git push origin branch-name推送自己的修改.如果推送失败,则因为远程分支比你的本地更新早,需要先用git pull试图合并。如果合并有冲突,则需要解决冲突,并在本地提交。再用git push origin branch-name推送。
合并(merge)和变基(rebase)
到底什么时候使用 merge 操作,什么时候使用 rebase 操作呢?
使用 merge 操作(保留合并的痕迹)
支持使用 merge 的开发者,他们认为仓库的提交历史就是记录实际发生过什么,它是针对于历史的一个文档,本身其实是有价值的,我们不应该随意修改。我们改变历史的话,就相当于使用“谎言”来掩盖实际发生过的事情,而这些痕迹是应该被保留的。可能,这样并不是很好。
使用 rebase 操作(不保留合并的痕迹)
支持使用 rebase 的开发者,他们认为提交历史是项目过程中发生过的事情,需要项目的主干非常的干净。而使用 merge 操作会生成一个 merge 的 commit 对象,让提交历史多了一些非常多余的内容。
当我们后期,使用 log 命令参看提交历史的话,会发现主干的提交历史非常的尴尬。比如,同样的修改内容重复提交了两次,这显然是分支合并导致的问题。
两者的使用原则
总的原则就是,只对尚未推送或分享给其他人的本地修改执行变基操作清理历史,从不对已经推送到仓库的提交记录执行变基操作,这样,你才可能享受到两种方式带来的便利。
附录
记住这些常用命令即可
1 | 工作区 -> 暂存区 |