版本控制简介
集中式版本控制系统(SVN)
版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。集中式版本控制系统最大的毛病就是必须联网才能工作。
分布式版本控制系统(GIT)
分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样工作的时候就不需要联网了。既然每个人电脑上都有一个完整的版本库,那多个人如何协作呢?比方说你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。
在实际使用分布式版本控制系统的时候,其实很少在两人之间的电脑上推送版本库的修改,因为可能你们俩不在一个局域网内,两台电脑互相访问不了,也可能今天你的同事病了,他的电脑压根没有开机。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑(GITHUB或GITLAB),但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。
初始设置
下载Git,安装完找到Git下Git Bash或右键选择Git Bash Here都可以打开Git命令窗口
首先需要设置我们的全局名字邮箱,用来辨别我们的电脑,后续需要的话可以单独对仓库设置,在Git Bash窗口执行下面命令
1 | git config --global user.name "Your Name" |
查看name和email
1 | git config user.name |
设置当前仓库name和email
1 | git config user.name "username" |
初始化本地仓库
版本库又称为仓库,英文名repository,可以简单理解成一个文件夹,这个文件夹里面的所有文件都被Git管理起来,每个文件的修改、删除都能跟踪,以便任何时刻都可以追踪或者在还原。
切换到要初始化为仓库的文件夹,执行命令
1 | git init |

工作区:指初始化的目录
版本库:初始化后工作区下有一个隐藏目录.git,就是Git的版本库。版本库中有暂存区(Index),还有Git自动创建的第一个主分支master,以及指向master的指针HEAD。
查看
查看仓库状态
1 | git status |
查看版本信息(即commit的记录)
1 | git log |
查看版本差异
1 | 比较工作区与暂存区 |
文件操作
添加文件
没有任何显示说明成功,Unix的哲学是“没有消息就是好消息”
1 | 提交单个文件 |
删除文件
- 用
git rm来删除文件,同时还会将这个删除操作记录下来; - 用
rm来删除文件,仅仅是删除了物理文件,没有将其从git的记录中剔除
1 | 删除文件 |
提交文件
1 | git commit -m 'commit TEST' |
撤销修改
正常GIT工作流程为3个步骤:(工作区) -> add(提交暂存区) -> commit(提交本地仓库) -> push(提交远程仓库)
对应产生5中状态:未修改(Origin) 、已修改(Modified) 、已暂存(Staged) 、已提交(Committed) 、已推送(Pushed)
已修改,未暂存
checkout命令是把在工作区的修改撤销,有两种情况:
- 修改后还没有被放到暂存区,那就会回退到版本库
- 已经添加到暂存区后,那就会回退到暂存区
1 | 撤销单个文件修改 |
已暂存,未提交
把最近一次提交的版本替换到暂存区 ,此操作不影响工作区
1 | git reset HEAD . |
已提交,未推送(版本回退)
在Git中,用HEAD表示当前版本,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本可以写成HEAD~100
回退到上一版本(即:把当前分支最近一次提交版本覆盖到工作区,把暂存区的修改全部撤销):
1 | git reset --hard HEAD^ |
Tips:回退后会看不到之前的版本号,可以用git reflog查看执行过的命令。如下查到回退前commit id为e4c3f5f,这样就可以用来回退到e4c3f5f
1 | git reflog |
Tips:Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当回退版本的时候,Git仅仅是把HEAD指针指向回退的版本
已推送
因为本地仓库和远程仓库是等价的,所以只需要先恢复本地仓库,再强制push到远程仓库即可
1 | git reset --hard HEAD^ |
分支管理
每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。主分支即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。
当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:
Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化
不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:
假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:
合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:
分支操作
创建分支:
1 | git branch dev |
切换分支:
1 | git checkout dev |
查看分支:
1 | 查看分支名称 |
合并分支:用于合并指定分支到当前分支
1 | git merge dev |
删除分支:
1 | 删除分支 |
简化分支线:
把分叉的提交历史“整理”成一条直线,看上去更直观,缺点是本地的分叉提交会被修改
1 | git rebase |
远程仓库
通过SHH验证
添加SSH KEY,不然无法推送数据到GITHUB
先在本地生成SSH key:
1 | ssh-keygen -t rsa -C "XXXXX@QQ.COM" |

用查看生成的KEY信息
填写到GITHUB中


新建远程仓库


克隆远程仓库
选择SSH验证,复制链接信息:
打开Git Bash Here克隆远程仓库
1 | git clone git@github.com:TationGH/testRepo.git |
新建分支
输入新建分支名,回车,下面会出现创建分支的选项,点击即可创建分支
后续就可以选择到新的分支了
如果远程仓库建了dev分支,本地仓库未建此dev分支,可以将远程dev分支拉取到本地
1 | git checkout -b dev origin/dev |
如果非上一步操作,而是本地和远程都单独建了dev分支,那就要先把两者先关联起来
1 | git branch --set-upstream-to=origin/dev dev |
查看
查看远程仓库库信息:
1 | git remote -v |
推送
推送当前分支到远程master分支
1 | git push origin master |
拉取
git fetch:
拉取时不会把远程分支版本合并当前分支上,而是将远程分支版本放到一个隐藏的commit,可以通过diff对比两个版本的差异,这样操作更安全,一般执行流程如下
1 | 拉取分支 |

git pull:
相当于:git pull = git fetch + git merge
少用git pull,用git fetch和git merge代替它
1 | git pull origin dev |
解决冲突
如果不同分支都对同一文件进行修改,合并有可能会提示冲突,大致输出错误信息如下:
1 | Auto-merging README.md |
打开冲突文件可以看到git将冲突内容用符号分割,内容大致如下:
1 | <<<<<<< HEAD |
Git用<<<<<<<,=======,>>>>>>>标记出不同分支两个版本冲突的内容,我们修改保存其中一个版本后,就可以重新提交后合并
存储现场
如果dev分支做了修改已add但不想commit,而此时需要用master开分支ISSUE-1修改BUG后提交,如果在ISSUE-1上修改会影响到工作区。可以把当前工作现场存储下来,工作区恢复到最后一次提交状态,等ISSUE提交完再恢复回来
1 | git stash |
查看存储的工作现场:
1 | git stash list |
恢复工作现场:
1 | 恢复最新的stash,stash内容并不删除,你需要用git stash drop来删除 |
标签管理
标签就是跟某个commit绑在一起有意义的名字,标签都只存储在本地,不会自动推送到远程
给commit id(f52c633)打上标签,用-a指定标签名,-m指定说明文字
1 | git tag -a v0.1 -m "version 0.1 released" 1094adb |
查看标签
1 | git show |
删除标签:
1 | git tag -d v1 |
推送标签到远程仓库:
1 | #推送某个标签到远程 |
删除远程仓库标签:
1 | git tag -d v1 |
忽略文件
使用文本编辑器创建一个.gitignore文件,提交到git,这样.gitignore文件里面写的文件名将被git忽略
1 | # gitignore file: |