002-GIT

版本控制简介

集中式版本控制系统(SVN)

版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。集中式版本控制系统最大的毛病就是必须联网才能工作。
c91f7a1db6242caba8dd3d05263fcc98

分布式版本控制系统(GIT)

分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样工作的时候就不需要联网了。既然每个人电脑上都有一个完整的版本库,那多个人如何协作呢?比方说你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。

分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。

在实际使用分布式版本控制系统的时候,其实很少在两人之间的电脑上推送版本库的修改,因为可能你们俩不在一个局域网内,两台电脑互相访问不了,也可能今天你的同事病了,他的电脑压根没有开机。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑(GITHUB或GITLAB),但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。
7fb6d77cc75d1c92645143593286f353

初始设置

下载Git,安装完找到Git下Git Bash或右键选择Git Bash Here都可以打开Git命令窗口
首先需要设置我们的全局名字邮箱,用来辨别我们的电脑,后续需要的话可以单独对仓库设置,在Git Bash窗口执行下面命令

1
2
git config --global user.name "Your Name"
git config --global user.email "email@example.com"

查看name和email

1
2
git config user.name
git config user.email

设置当前仓库name和email

1
2
git config user.name "username" 
git config user.email "useremail"

初始化本地仓库

版本库又称为仓库,英文名repository,可以简单理解成一个文件夹,这个文件夹里面的所有文件都被Git管理起来,每个文件的修改、删除都能跟踪,以便任何时刻都可以追踪或者在还原。

切换到要初始化为仓库的文件夹,执行命令

1
git init

91058a1a25b6aeb49893e67642533150
工作区:指初始化的目录
版本库:初始化后工作区下有一个隐藏目录.git,就是Git的版本库。版本库中有暂存区(Index),还有Git自动创建的第一个主分支master,以及指向master的指针HEAD。
9840f0fcc7cc28ec3b810f4d73fc85bf

查看

查看仓库状态

1
git status

查看版本信息(即commit的记录)

1
2
3
git log
查看简要信息
git log --pretty=oneline

查看版本差异

1
2
3
4
5
6
7
8
9
10
11
12
比较工作区与暂存区
git diff
比较暂存区与最新本地版本库
git diff --cached [<path>...]
比较工作区与最新本地版本库
git diff HEAD [<path>...]
比较工作区与指定commit-id的差异
git diff commit-id [<path>...]
比较暂存区与指定commit-id的差异
git diff --cached [<commit-id>] [<path>...]
比较两个commit-id之间的差异
git diff [<commit-id>] [<commit-id>]

文件操作

添加文件
没有任何显示说明成功,Unix的哲学是“没有消息就是好消息”

1
2
3
4
5
6
7
8
提交单个文件
git add TEST.txt
提交所有变化
git add -A
提交被修改(modified)和被删除(deleted)文件,不包括新文件(new)
git add -u
提交新文件(new)和被修改(modified)文件,不包括被删除(deleted)文件
git add .

删除文件

  • git rm来删除文件,同时还会将这个删除操作记录下来;
  • rm来删除文件,仅仅是删除了物理文件,没有将其从git的记录中剔除
1
2
3
4
5
6
7
8
删除文件
git rm test.file
git commit -m "delete test.file"
或者
rm test.file
git commit -am "delete test.file"
切换到要删除文件的目录下,批量删除文件
git rm * -r

提交文件

1
git commit -m 'commit TEST'

撤销修改

正常GIT工作流程为3个步骤:(工作区) -> add(提交暂存区) -> commit(提交本地仓库) -> push(提交远程仓库)
对应产生5中状态:未修改(Origin) 、已修改(Modified) 、已暂存(Staged) 、已提交(Committed) 、已推送(Pushed)

已修改,未暂存

checkout命令是把在工作区的修改撤销,有两种情况:

  1. 修改后还没有被放到暂存区,那就会回退到版本库
  2. 已经添加到暂存区后,那就会回退到暂存区
1
2
3
4
撤销单个文件修改
git checkout -- TEST.txt
撤销所有文件修改
git checkout .

已暂存,未提交

把最近一次提交的版本替换到暂存区 ,此操作不影响工作区

1
git reset HEAD .

已提交,未推送(版本回退)

在Git中,用HEAD表示当前版本,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本可以写成HEAD~100
回退到上一版本(即:把当前分支最近一次提交版本覆盖到工作区,把暂存区的修改全部撤销):

1
git reset --hard HEAD^

Tips:回退后会看不到之前的版本号,可以用git reflog查看执行过的命令。如下查到回退前commit id为e4c3f5f,这样就可以用来回退到e4c3f5f

1
2
3
4
5
6
7
git reflog

5ac930c HEAD@{0}: reset: moving to HEAD^
e4c3f5f HEAD@{1}: commit: commit 2 TEST

#回退
git reset --hard e4c3f5f

Tips:Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当回退版本的时候,Git仅仅是把HEAD指针指向回退的版本

已推送

因为本地仓库和远程仓库是等价的,所以只需要先恢复本地仓库,再强制push到远程仓库即可

1
2
git reset --hard HEAD^
git push -u origin master

分支管理

每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。主分支即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。
659cb5a539b59dfe8d922d9fa10c7c66
当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:
43776405ce0fc1d28a06f0f466bc9b29
Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化
不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:
8b2412968818b2de51f32b2d8a7f0084
假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:
1ac1e2230a397818ca0ffe00bd81341c
合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:
dbcac08f816441b507bd9a8ca2026acb

分支操作

创建分支:

1
git branch dev

切换分支:

1
git checkout dev

查看分支:

1
2
3
4
查看分支名称
git branch
查看分支树状结构
git log --graph --pretty=oneline --abbrev-commit

合并分支:用于合并指定分支到当前分支

1
git merge dev

删除分支:

1
2
3
4
5
6
删除分支
git branch -d dev
一个没有被合并过的分支,如果要强行删除,需要使用大写的-D参数
git branch -D test
删除远程分支
git branch origin :dev

简化分支线:
把分叉的提交历史“整理”成一条直线,看上去更直观,缺点是本地的分叉提交会被修改

1
git rebase

远程仓库

通过SHH验证

添加SSH KEY,不然无法推送数据到GITHUB
先在本地生成SSH key:

1
ssh-keygen -t rsa -C "XXXXX@QQ.COM"

4fce1d974c5bdabc49d892f4b2265da1
用查看生成的KEY信息
352aaa59cb245b073a9be19de022bfd6
填写到GITHUB中
6e0469e937b43e9071c1c6bfb00cb374
7e504a699345a8c1e52b28faf9aa3523
f13b4a5056dc6894051606aab352b4c5

新建远程仓库

006676ed2392cf2904168023ba15e2bb
0e48bb1f5ac68269b58f1c67aad08d28

克隆远程仓库

选择SSH验证,复制链接信息:
de886ed86c23708e595cfe162ed20acf
打开Git Bash Here克隆远程仓库

1
git clone git@github.com:TationGH/testRepo.git

新建分支

输入新建分支名,回车,下面会出现创建分支的选项,点击即可创建分支
d3f2acad852361b9a38ca204dc596f14
后续就可以选择到新的分支了
398c4b04501204a05c756e2a8b8038a4
如果远程仓库建了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
2
3
4
5
6
拉取分支
git fetch origin dev
对比差异
git diff origin/dev
合并分支
git merge origin/dev

271aedece4421cd5c3e4f4bff6704fb4
git pull:
相当于:git pull = git fetch + git merge
少用git pull,用git fetch和git merge代替它

1
git pull origin dev

解决冲突

如果不同分支都对同一文件进行修改,合并有可能会提示冲突,大致输出错误信息如下:

1
2
3
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md #合并发生冲突
Automatic merge failed; fix conflicts and then commit the result.

打开冲突文件可以看到git将冲突内容用符号分割,内容大致如下:

1
2
3
4
5
<<<<<<< HEAD
11111
=======
22222
>>>>>>> dev

Git用<<<<<<<,=======,>>>>>>>标记出不同分支两个版本冲突的内容,我们修改保存其中一个版本后,就可以重新提交后合并
f9136e15d9d05da25797a31643ff834f

存储现场

如果dev分支做了修改已add但不想commit,而此时需要用master开分支ISSUE-1修改BUG后提交,如果在ISSUE-1上修改会影响到工作区。可以把当前工作现场存储下来,工作区恢复到最后一次提交状态,等ISSUE提交完再恢复回来

1
git stash

查看存储的工作现场:

1
git stash list

恢复工作现场:

1
2
3
4
5
6
恢复最新的stash,stash内容并不删除,你需要用git stash drop来删除
git stash apply
恢复指定的stash
git stash apply stash@{0}
恢复的同时把stash内容也删除
git stash pop

标签管理

标签就是跟某个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
2
3
4
#推送某个标签到远程
git push origin v1
#一次性推送全部尚未推送到远程的本地标签
git push origin --tags

删除远程仓库标签:

1
2
git tag -d v1
git push origin :refs/tags/v1

忽略文件

使用文本编辑器创建一个.gitignore文件,提交到git,这样.gitignore文件里面写的文件名将被git忽略

1
2
3
# gitignore file:
test.txt
*.exe