git真的是一个很方便的一个工具,非常值得学习,而且搭配github使用或者是多人项目的开发,真的是很牛x。
分布式与集中式
学习之前了解一下分布式与集中式
假如我们要办一件事,一个人包揽就是集中式,一件事分成几个部分分成几个人做就是分布式,二者最取得的效果是一样的。
比如一个javaweb的项目,我们把它简单的分成web页面服务:数据库服务,service服务。
集中式: 我们将它部署在服务器上,如果服务器出了问题,这个网站就崩了。
分布式: 上面的三个,我们用独立服务器放,同一类我们还可以用多个服务器组成,即使一个崩了,还有其他的服务器顶着。
集中式版本控制: 版本库存放在中央服务器,每次工作都要从中央服务器取出最新的版本,修改以后再提交上去,一旦服务器崩了,或者没网了,工作无法执行。
分布式版本控制: 没有中央服务器,每个人的电脑上都有一个完整的版本库,每次工作完以后只要将每次的修改提交给对方就行了。
git的使用
git使用前的最小配置
git config –global user.name ‘your_name’
git config –global user.email ‘your_email@domain.com’
缺省等同于local
- git config –local local只对某个仓库有效
- git config –global global对当前用户的所有仓库有效
- git config –system system对系统所有登录的用户有效
在当前仓库中,如果设置了local的话,local优先级要高,system指令用不上
查看一些配置信息:
- git config –list –local 只在某一个仓库有效
- git config –list –global 所有仓库有效
- git config –list –system
了解工作区,暂存区,历史版本库
git是如何保存数据的
git存储文件的方式不是存储文件的变化或者差异,他存储的是一系列不同时刻文件的 快照 .例如,每次你执行 git add 或者 git commmit 操作,就会将文件压缩成一个二进制文件,这就是一个Git对象,存在于 ==.git/objects== 目录下。文件的名字是用SHA1算法计算的一个hash值(长度40的字符串), ==.git/objects== 下成一个子目录,前两个字符是子目录名,后38位是文件名。
.git文件
两个比较重要的文件:
refs/
heads -分支 (例如:前端分支,后端分支,两者互不影响)
tags -里程碑 (标签)HEAD - 查看当前仓库在哪个分支上
conig - 仓库信息
objects - 存储每次操作的二进制文件
git中文件的几种状态
Untracked: 未跟踪, 此文件在文件夹中, 但并没有加入到git库, 不参与版本控制. 通过git add 状态变为Staged.
Unmodify: 文件已经入库, 未修改, 即版本库中的文件快照内容与文件夹中完全一致. 这种类型的文件有两种去处, 如果它被修改, 而变为Modified.
Modified: 文件已修改, 仅仅是修改, 并没有进行其他的操作. 这个文件也有两个去处, 通过git add可进入暂存staged状态, 使用git checkout 则丢弃修改过,返回到unmodify状态, 这个git checkout即从库中取出文件, 覆盖当前修改
Staged: 暂存状态. 执行git commit则将修改同步到库中, 这时库中的文件和本地文件又变为一致, 文件为Unmodify状态. 执行git reset HEAD filename 取消暂存,文件状态为Modified
git的常用操作
1. 查看工作区状态
1 | git status |
2. 工作区提交到暂存区
对暂存区文件的修改:添加,删除,更新
1 | git add <file-name> |
3. 暂存区提交到版本库
1 | git commit -m 'message' |
4. 查看历史版本
1 | git log //查看所有版本历史 |
5. 比较文件差异
1 | git diff [--<file-nameA> [<file-nameB>]] //比较工作区与暂存区差异,加文件名就只比较文件(可以比多个)的差异 |
6. 删除工作区和暂存区文件
1 | git rm <file-name> |
7. 工作区同步与暂存区一样
1 | git checkout -- <file-nameA> [file-nameB] |
8. 暂存区同步与历史版本库一样
1 | git reset <branch-name> //同步到某一个分支 |
9. 版本回溯
1 | git reset --soft <commit-id> |
git reset 影响范围 | |||
指令 | HEAD | 暂存区 | 工作区 |
--soft | 是 | 否 | 否 |
--mixed | 是 | 是 | 否 |
--hard | 是 | 是 | 是 |
10. 合并分支
– 基于 merge
1 | git merge <merge-nameA> |
1 | git merge --abort //如果不想合并,此命令会返回合并之前的状态 |
fast-forward(快进)与non-fast-forward
分支合并,其中一个分支,是另外一个分支的父分支,叫做fast-forward,否则就是non-fast-forward
merge操作:利用三路合并算法,merge结果与时间先后无关,就是两个人分支会找到一个基准Base(历史版本中的某一次commit,简单情况下就是分支分叉的位置),如果两个文件相对于Base都不一样,就会产生冲突,需要手动解决。查看两个分支的Base命令: git merge-base <merge-nameA> <merge-name-B>。merge之前的文件在merge过程中可以导出查看。
– 基于 rebase的变基操作
将一个分支的修改移到另外一个分支上,好像”重新播放”一样.
1 | git rebase <branchA> //相当于在B分支上,把B整合到A上,A,B最近的共同父分支(就是分叉的位置)往后的B分支都不见了,会在A分支后生成一段新的提交。这样,提交历史就是一条干净的直线了。 |
最好是在提交到远程仓库之前之前,将自己的版本库进行一次变基操作,再向主项目提交。
变基操作的准则:不要对在你的仓库外有副本的分支执行变基。
11. 修改工作区和暂存区文件名
1 | git mv <old-name> <new-name> |
12. 关于分支的操作
– 创建分支
1 | git branch <new-branch-name> |
– 查看分支
1 | git branch [-v] |
– 切换分支
1 | git checkout <branch-name> |
– 删除分支
1 | git branch -d <branch-name> |
13. 将多个commit整理成一个commit
– 不连续的commit
1 | git rebase -i <要整合的最早的一个commit> |
演示:
先看一段版本历史:
容易看出版本号为: d09341c ,e3a6b32 ,603e2b3 都是对readme.md的操作,我们想整理成一次commit。
先找到要整合的最早的commit的版本号 为 603e2b3
执行:git rebase -i 603e2b3
进入界面:
修改后:
注意看p,s均为简写,下方有注释
退出后,执行 git rebase --continue
进入界面:
添加注释:
-- 连续的commit
1 | git rebase -i <整合的最早的一个commit> |
类似上方,更简单。
14. 消除最近的几个commit
1 | git reset --hard <commit-number> //工作区和暂存区都会恢复成指定的commit版本号的内容(慎用) |
15. 开发中如果紧急加塞怎么处理
git stash会将此时工作区和暂存区的内容压入Git的栈中,工作区就是干净的了,此时工作区的内容会和上次的commit内容一样。来避免一次脏提交。
1 | git stash: //备份当前的工作区和暂存区的已经被track的文件,保存到Git栈中。从最近的一次提交中读取相关内容,让工作区保证和上次提交 |
多人协作以及GitHub的使用
git备份
哑协议与智能协议
直观区别:哑协议传输进度不可见;智能协议传输可见
传输速度:智能协议比哑协议传输速度快
常用协议 | 语法格式 | 说明 |
---|---|---|
本地协议(1) | /d/Desktop/gitcommit/commit2/.git | 哑协议 |
本地协议(2) | file:///d/Desktop/gitcommit/commit2/.git | 智能协议 |
http/https协议 | https://github.com/name/learngit.git | 平时接触到的都是智能协议 |
ssh协议 | git@github.com:name/learngit.git | 工作中最常用的智能协议 |
多人协作
git clone的使用
- git clone <版本库的网址> [file-name]
如果附带[file-name],则会生成一个目录名字为[file-name],默认则为版本库的名字。(注意网址后面是附带.git的)版本库的网址>
git remote的使用
- git remote [-v]
查看远程主机 [与网址] - git remote add <主机名> <网址>
添加主机网址>主机名> - git remote rename <原主机名> <新主机名>
修改主机名字新主机名>原主机名> - git remote rm <主机名>
删除主机主机名> - git remote show <主机名>
查看主机信息主机名>
git fetch的使用
- git fetch <远程主机名> [分支名]
取回远程主机所有分支的更新(若附带括号则取指定分支名的更新)远程主机名>
git push的使用
git push <远程主机名> [远程分支名]:[本地分支名]远程主机名>
git pull的使用
- git pull <远程主机名> <远程分支名>:<本地分支名>
取回远程主机的指定分支,并与指定本地分支合并(一个git pull操作等于先git fetch再git merge)本地分支名>远程分支名>远程主机名>
在git clone的过程中,Git会在本地分支与远程分支之间建立一种追踪关系(tracking)。例如,git clone过程中,所有本地分支默认与远程主机的同名分支,建立追踪关系,也就是说,本地的master分支自动"追踪"origin/master分支。
Git也允许手动建立追踪关系
git branch --set-upstream <本地分支名> <远程仓库名>/<远程分支名>远程分支名>远程仓库名>本地分支名>
如果当前分支与远程分支存在追踪关系,git pull就可以省略远程分支名。
git pull <远程仓库名>远程仓库名>
第一次提交到非空GitHub仓库
例如:github初始化时,带有readme和开源协议
记得git pull一下
不同人的人修改了不同的文件
1 | $ git push github chase |
先 merge一下再push
不同的人修改了相同文件的不同位置
同上,git会自己整合
不同的人修改了相同文件的相同位置
同上操作,不过此时,会提示冲突,git会自己整合,但是需要自己解决冲突
不同的人同时变更了文件名和文件内容
例如:
- (先)A修改 index.html 为 index.htm 并且 push到远程仓库
- (后)B修改 index.html (B不知道文件名已经被修改了),并且修改了文件的内容,push到远端,发现错误,git pull(等同于上面的 git fetch 再 git merge) 一下,发现git自动识别出来,就是git会将B仓库下的 index.html 修改成 index.htm ,并且内容被修改,再push到远程仓库即可
不同的人同时修改了文件名
- (先)A修改了 index.html 为 index1.html ,并且push到远端
- (后)B修改 index.html 为 index2.html ,push到远端报错, git pull 到本地,发现发生冲突,这时候需要手动解决冲突, git status 会发现,工作区有两个文件 index1.html index2.html , git status 发现暂存区提示 这时候你需要和你的同伴讨论最后的名字是哪一个,然后手动删除不需要的两个文件,提交另外一个即可,再 git push 到远程仓库。
1
2
3both deleted: index.html
added by them: index1.html
added by us: index2.html
FETCH_HEAD
FETCH_HEAD是一个短期引用,以跟踪刚刚从远程存储库获取的内容。 git pull首先调用git fetch,在正常情况下从远程获取一个分支; FETCH_HEAD指向这个分支的提示(它存储提交的SHA1,就像分支一样)。 git pull然后调用git merge,将FETCH_HEAD合并到当前分支。
团队协作中禁止的操作
- git push -f
- 禁止向集成分支执行变更历史操作(变基操作)
如何在Github上找到想要的开源项目呢
进入链接: https://github.com/search/advanced
或者在搜索栏空搜,
github的help中有教怎么用,或者看看这个链接吧.
1 | 补充:https://www.jianshu.com/p/450cd21b36a4 |