Skip to content

Latest commit

 

History

History
376 lines (191 loc) · 17.4 KB

git-guide.md

File metadata and controls

376 lines (191 loc) · 17.4 KB

Git的基本使用

创建版本库

什么是版本库呢?

版本库又名仓库,英文名repository,简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。由于git是分布式版本管理工具,所以git在不需要联网的情况下也具有完整的版本管理能力。

创建一个版本:

1)首先,选择一个合适的地方,创建一个空目录.

2)使用 git init 命令把这个目录变成Git可以管理的仓库:

命令输入后,会提示你,已经创建了一个空的Git仓库。目录下可以发现一个隐藏目录.git

目录默认是隐藏的,用ls -ah命令就可以看见。

目录就是我们的:工作区,存放所有当前文档。此目录下的文件才会被Git管理

.git目录就是我们的:本地仓库,管理并保存所有的文档变化及历史状态。

总结:创建版本库的步骤:

1) 进入需要管理的目录

2) 执行 git init 命令

添加文件并提交

版本控制系统,其目的就是跟踪文本文件的改动,例如我们开发时编写的.java、.xml、.properties本质都是文本文件。文件中每一个字符的变化都会被跟踪并且管理。

将一个文件添加到本地仓库,分两步:

1) 使用 git add <file> 命令,添加文件。可以一次添加多个文件。

2) 使用git commit命令,提交,一次即可。

note:首次使用需要告诉git,当前用户的基本信息

工作区、暂存区、版本库

理解Git 工作区、暂存区和版本库概念

工作区:

工作区就是你在电脑里能看到的目录。比如新创建的目录:

其中包含了一个隐藏目录 .git ,其它就是我们需要被管理的文件。

版本库及暂存区:

工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。

Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。

把文件往Git版本库里添加的时候,是分两步执行的:

第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;

第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。

因为创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。

可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。

管理文件修改

被版本库管理的文件不可避免的要发生修改,此时只需要直接对文件修改即可。修改完毕后需要将文件的修改提交到版本库。

差异比较:

git diff -- readme.txt命令可以查看工作区和版本库里面最新版本的区别

查看状态,提交修改:

我们如果不确定自己的哪些文件被修改了,可以使用git status 命令,查看当前工作区的状态:

可以清楚的看到:changes not staged for commit(修改没有被缓存,需要使用git add来进行添加操作)

我们使用git add 命令,添加到暂存区:

这次提示: changes to be commited (修改需要被提交),我们使用git commit 进行提交

提示说:工作区很干净,没有任何需要提交,搞定

版本回退

日志查看:

我们通过 git log 命令,可以查看历史的每次提交信息:

如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline参数:

可以发现,目前为止,我们已经在本地仓库中提交了3次,也就是说有3个不同版本。其中,最近的这个版本有一个标示:HEAD ,这就是标记当前分支的当前版本所在位置。本例当中,当前版本即 test version control这次提交。

另外,在log中,每一个版本的前面,都有一长串随机字符串:5bc7781319b…192728 ,这是每次提交的commit id ,这是通过SHA1算法得到的值,Git通过这个唯一的id来区分每次提交。

版本回退:

首先,Git通过HEAD来判断当前所在的版本位置。写成HEAD~100。

查看所有关联日志:

可以通过git reflog命令,看到以前的每次执行动作:

通过指定commit id 的方式,来指定HEAD的位置:

指令:git reset --hard {commit id}

总结:

如果要进行版本回退或前进,一般分两步:

1) 通过git log 或 git reflog 查看操作日志吗,查找版本的commit id

2) 通过 git reset --hard 设置HEAD到指定版本

其实版本的回退,仅仅是修改HEAD指针的位置而已,因此Git进行版本的切换,比svn要快的多!

撤销修改

撤销工作区修改

查看状态,Git提示我们,现在文件已经修改,等待被staged(暂存)。我们有两个选择:

1) 可以使用git add 来添加到暂存区,接着去提交文件

2) 可以使git checkout -- 来撤销修改

这里我们选择第二种方案,即可看到修改已经被撤销了!

撤销staged(暂存区)修改

查看状态,有修改等待被提交,并且有一行提示,可以使用 git reset HEAD 来撤销缓存修改。

前面说过,git reset 命令可以进行版本回退,此处reset 指定的是HEAD ,而不是其他版本,因此就有撤销缓存修改的作用:

查看状态,发现文件的修改被撤回到了工作区,尚未添加到staged(暂存区),我们再次执行git checkout -- 即可撤销工作区修改

总结:

撤销修改分两种情况:

1) 撤销工作区修改,使用git checkout --

2) 撤销暂存区修改,分两步:

a) 使用git reset HEAD 来撤销暂存区修改。

b) 使用git checkout -- 来撤销工作区修改

远程仓库

上述基本使用是在本机利用git进行文件版本管理,但是如果要想进行多人协作,我们就必须使用远程仓库。将本地仓库的数据同步到远程仓库,实现多人协作开发。

目前比较热门的代码托管社区:GitHub,码云

当然,也可以自己来搭建远程仓库。

访问远程仓库

填写项目信息,仓库创建完毕,可以看到,如果要与远程仓库同步,这里支持两种不同的通信协议,ssh和http。当我们选中一种协议后,后面会出现对应的远程仓库地址。

推荐使用ssh协议。因为http速度较慢,并且每次都需要验证用户名和密码。

但是要使用SSH协议进行同步,你就必须生成SSH密钥,并添加到当前仓库的许可列表中!

SSH协议

什么是ssh?

SSH是英文Secure Shell的简写形式。通过使用SSH,你可以把所有传输的数据进行加密,这样"中间人"这种攻击方式就不可能实现了,而且也能够防止DNS欺骗和IP欺骗。

使用SSH,还有一个额外的好处就是传输的数据是经过压缩的,所以可以加快传输的速度。SSH有很多功能,它既可以代替Telnet,又可以为FTP、Pop、甚至为PPP提供一个安全的"通道"。

如果一个用户从本地计算机,使用SSH协议登录另一台远程计算机,我们就可以认为,这种登录是安全的,即使被中途截获,密码也不会泄露。

最早的时候,互联网通信都是明文通信,一旦被截获,内容就暴露无疑。1995年,芬兰学者Tatu Ylonen设计了SSH协议,将登录信息全部加密,成为互联网安全的一个基本解决方案,迅速在全世界获得推广,目前已经成为Linux系统的标准配置。

创建SSH密钥

Git-bash中已经集成了ssh功能,所以我们只需要简单的命令,即可生成密钥:ssh-keygen -t rsa

一路回车向下走,不要输入任何内容即可.

执行命令完成后,在window本地用户.ssh目录C:\Users\用户名.ssh下面生成如下名称的公钥和私钥

添加SSH密钥到git私服:

选择用户,个人设置,点击SSH密钥设置,并添加密钥,密钥的内容,就是刚刚生成的两个密钥中的公钥:id_rsa.pub

将这段公钥添加到用户,这就说明,这台公钥的机器具备了访问这个git账号中的远程仓库的权限

推送远程仓库

关联远程仓库:

git remote add origin [email protected]:taft31/payou.git

推送本地仓库到远程仓库的master分支:

git push -u origin master

需要注意的是:git remote add origin 后面紧跟的,其实是上面的仓库地址信息

执行命令,发现有提示信息,推送成功!此时登录远程仓库,刷新页面,可以看到数据已经推送,并且与本地仓库完全一致

从现在起,只要本地作了提交,就可以通过命令:

git push origin master

把本地master分支的最新修改推送至GitEE,现在就拥有了真正的分布式版本库

克隆远程仓库

现在,假设一个新的成员要加入我们的开发队伍,那他首先要做的第一件事情,一定是从远程仓库获取所有代码。此时就可以使用克隆动作。克隆远程仓库:就是从远程把仓库复制一份到本地,克隆后会创建一个新的本地仓库。

找到一个目录 ,打开控制台,输入命令:git clone 远程仓库地址

拉取远程仓库数据

现在如果有人也向远程仓库推送了代码,那么当我们就需要拉取 远程仓库的最新代码到本地:

在本地拉取最新代码,使用git pull 命令

总结:

1) 如果要使用SSH协议与远程仓库同步,就必须先在本地生成公钥和私钥,然后将公钥添加到远程的SSH列表

2) 如果已经有本地仓库,并且想要与远程仓库关联,一般需要两步:

a) 通过git remote add origin + 远程仓库地址 进行关联

b) 通过git push -u origin master推送本地仓库修改到远程仓库

c) 通过git pull 命令拉取远程库数据

3) 如果没有本地仓库,先创建远程仓库,然后通过git clone + 远程仓库地址 进行克隆并创建本地仓库

分支管理

分支作用

假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。

现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。

Git的分支是与众不同的,无论创建、切换和删除分支,Git在1秒钟之内就能完成!无论你的版本库是1个文件还是1万个文件。

Git的分支管理原理

我们的每次提交,都对应一个具体的时间点,git会把这许多的时间点串起来,就形成了一条时间线,这条时间线就是一个分支。Git中默认的分支就是主分支,叫master。

我们查看当前的提交日志,发现总共有3次提交,这3次提交可以串起来成一条时间线,就是master分支:

每次提交,master分支都会新增一个时间点,分支线也不断变长。

当我们创建新的分支,例如dev分支,原来指向master的指针,就要指向新的dev分支,相同的时间点(提交点),这样分支就创建好了,你的工作区无需任何改变,创建分支的速度非常的快。

而要切换分支,只需要把HEAD指向dev即可,所以你的分支实现了光速切换!

不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:

假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:

所以Git合并分支也很快!就改改指针,工作区内容也不变!

合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:

你会发现Git的分支管理,基本就是创建新的指针,改变HEAD指向,删除指针等操作,几乎没有文件的增删。所以速度非常快!

分支的创建和合并

创建分支:

可以使用 git checkout -b 分支名 来创建并切换到新的分支:

注意到我们已经切换到了dev分支。 git checkout 加上 -b 参数,就等同于创建分支,并切换分支。相当于以下两条命令:

git branch dev # 创建分支

git checkout dev # 切换到具体分支

使用git branch 查看所有分支,当前分支前面会有一个*表示:

合并分支:

使用git checkout master切换回master分支,查看内容:

发现readme并没有改变,因为刚才修改的是dev分支。此时的HEAD已经指向了master了:

我们使用git merge dev命令将 dev分支的修改合并到master分支:

git merge命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就可以看到,和dev分支的最新提交是完全一样的。

删除分支:

合并完成后,就可以放心地删除dev分支了,可以使用git branch -d dev 命令删除dev分支,dev就是具体的分支名

总结:

1) 使用git branch 分支名 创建分支

2) 使用git checkout 分支名 来切换分支

3) 也可以使用 git checkout -b 分支名 来完成 创建并切换分支的操作

4) 使用git merge 分支名 来合并分支到当前分支

5) 使用git branch -d 分支名 来删除指定分支,注意:要删除一个未合并的分支。需要使用-D参数进行强制删除

解决冲突

制造冲突

现在我们新建一个分支dev,然后修改readme.txt,将dev的修改提交;

切换到master分支,并且在readme.txt最后添加内容,提交数据:

master和dev都有了各自新的提交,就出现冲突

解决冲突

这种情况下,是无法进行快速合并的。我们试一下,自动合并失败,必须先解决文件冲突,才能提交。

此时查看readme.txt文件,我们可以根据实际情况进行冲突解决,比如两者都保留,然后再次提交:

工作区就干净了。此时master和dev分支线就变成了这样:

可以用git log --graph --pretty=oneline --abbrev-commit命令来查看:

接下来就可以删除dev分支了。

保存工作区状态

现在假设这样一个场景,我们正在dev上进行开发,代码进行了一半,突然线上出现了一个紧急BUG需要你进行修复。我们可以创建一个新的hotFix分支来进行修复,但是等等。我当前的dev分支还有未提交的修改,怎么办?如果直接切换到新的分支,那么当前dev 的工作就白费了!有同学可能会说,我们先把代码提交啊,回头再接着写。但是这样的提交是不合理的,也没有任何实际意义的,因为你的代码并没有完成,你提交的是不完整的功能!

git给我们提供了stash功能,可以把当前工作区的内容进行“快照”,等待以后恢复使用。

实际操作,首先,我们创建并切换到dev分支:

修改readme.txt,查看状态,显然,readme有修改待提交。但是现在我们需要去进行紧急的BUG修复,没办法继续开发dev。

我们使用stash命令:

发现工作区已经被保存起来了,并且工作区再次变成了clean,可以放心的去新的分支修复BUG了。

我们切换回master,现在假设你修复完成了BUG,bug修复完成,然后我们再次回到dev分支去查看:

工作区是干净的,我们之前的修改去哪里了呢?通过git stash list命令来查看

工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:

1) 方式1:用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;

2) 方式2:用git stash pop,恢复的同时把stash内容也删了:

3) 注意,以上指令都可以在后面紧跟 stash的序号,来操作指定stash,例如: git stash apply stash@{0}

客户端工具(TortoiseGit)

现在Git的客户端工具非常多,比较流行的例如:TortoiseGit(在svn中俗称小乌龟)、SourceTree。

安装和使用的原理和git命令方式是类似的,不再赘述.需要做一些配置,具体参考源文档.

.gitignore文件的语法:

l  空行或是以#开头的行即注释行将被忽略。
l  可以在前面添加正斜杠/来避免递归,下面的例子中可以很明白的看出来与下一条的区别。
l  可以在后面添加正斜杠/来忽略文件夹,例如build/即忽略build文件夹。
l  可以使用!来否定忽略,即比如在前面用了*.apk,然后使用!a.apk,则这个a.apk不会被忽略。
l  *用来匹配零个或多个字符,如*.[oa]忽略所有以".o"或".a"结尾,*~忽略所有以~结尾的文件(这种文件通常被许多编辑器标记为临时文件);[]用来匹配括号内的任一字符,如[abc],也可以在括号内加连接符,如[0-9]匹配0至9的数;?用来匹配单个字符。