Git && GitHub 教程
1.Git 基本概念
-
版本控制:一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统
-
集中化的版本控制系统,如CVS,SVN
-
优点:代码存放在单一的服务器上便于项目的管理
svn 每次存储的都是版本与版本之间的差异,所需的硬盘空间会相对较小,但是回滚的速度会很慢
最大缺点是单点故障 ;服务器宕机,服务器炸了
-
分布式的版本控制系统,如Git,客户端并不只是提取最新版本的文件快照,而是把代码仓库完整地镜像下来(去中心化思想)
git每次存的是项目的完整快照,需要的硬盘空间会相对较大(Git团队对代码做了极致的压缩,最终需要的实际空间比SVN多不了多少,可是Git的回滚速度很快)
2.简介&安装
git config --global user.name “user”
git config --global user.email user@example.com
git config --list 查看相关配置
3.Linux 基本命令
3.1 区域
- 工作区
- 暂存区
- 版本库
3.2 对象
- Git 对象
- 树对象
- 提交对象
3.3 底层命令
-
初始化命令 git init
-
基础Linux命令
4. Git 对象
- Git 的核心部分是一个简单的键值对数据库,你可以向该数据库插入任意类型的内容,他会返回一个键值,通过该键值可以在任意时刻再次检索该内容
- git hash-object -w 文件路径
-w 选项指示要存储数据对象;若没有的话,只是返回该内容对应的键值
向数据库写入内容,并返回对应的键值
-
git cat-file -p hash值
-
Git 对象 就是key:value 键值对,(key是value对应的hash) blob类型
-
问题:
1.记住文件的每一个版本所对应的SHA-1值并不现实
2.在Git中,文件名并没有被保存——我们仅保存了文件的内容
解决方案:树对象
注意:当前的操作都是再对本地数据库进行操作,不涉及暂存区
5.树对象
-
树对象(tree object),它能解决文件名保存的问题,也允许我们将多个文件组织到一起。Git 以一种类似于UNIX文件系统的方式存储内容。所有内容均以树对象和数据对象(Git对象)的形式存储,其中树对象对应了UNIX中的目录项,数据对象(Git对象)则大致对应文件内容。一个树对象包含了一条或多条记录(每条记录含有一个指向Git对象或者子树对象的SHA-1指针,以及相应的模式、类型、文件名信息)。一个树对象也可以包含另一个树对象
-
构建树对象,可以通过update-index ; write-tree ; read-tree 等命令来构建树对象并塞入到暂存区
-
git ls-files -s 查看暂存区内容
-
git对象 是一个文件的版本快照,树对象是一个项目的版本快照,项目的一个版本就是一个提交对象
6.提交对象
- 我们可以通过调用commit-tree命令创建一个提交对象,为此需要指定一个树对象的SHA-1值,以及该提交的父提交对象(如果有的话,第一次将暂存区做快照就没有父对象)
- 提交对象对树对象进行了封装,包括注释,作者等信息,并且是链式的
7.高层命令 基础
-
git操作最基本的流程
-
创建工作目录,对工作目录进行修改 git init
-
git add ./
- git hash-objects -w 文件名(修改了多少个工作目录中的文件,此命令就被执行多少次)存到本地数据库
- git update-index … 放入暂存区
-
git commit -m “注释内容”
- git write-tree 生成树对象
- git commit-tree 生成提交对象
-
8. 高层命令(CRUD)
- git init 初始化仓库
- git add ./ 将修改添加到暂存区
- git commit -m 注释内容 将暂存区提交到版本库
- git status 查看文件的当前状态
- git diff 查看哪些修改还没有暂存
- git diff --cached 有哪些更新已经暂存起来准备好下次提交
- git commit -a -m 跳过使用暂存区域,加上-a,Git会自动把所有已跟踪过的文件暂存起来一并提交,跳过git add 步骤
- git log 查看提交的历史记录
- git log --pretty=oneline / git log --oneline
- 工作目录下的所有文件都不外乎两种状态:已跟踪 或 未跟踪
已跟踪的文件是指本来就被纳入版本控制管理的文件,在上次快照中有他们的记录,工作一段时间后,他们的状态可能是已提交,已修改 或者 已暂存
所有的其他文件都属于未跟踪文件。他们既没有上次更新时的快照,也不再当前的暂存区域。
初次克隆某个仓库时,工作 目录中的所有文件都属于已跟踪文件,且状态为已提交;在编辑过某些文件之后,Git将这些文件标记为已修改。我们逐步把这些修改过的文件放到暂存区域,知道最后一次性提交所有这些暂存起来的文件。
- 已修改 呈红色; 已暂存(等待提交) 呈绿色; 已提交 为空
9. 高层命令(删除和重命名)
- git rm 文件名 在本地目录删除该文件,并将修改添加到暂存区
- git mv 原文件名 新文件名 将工作目录中的文件进行重命名,并将修改添加到暂存区
10. 高层命令 (分支基础)
-
HEAD 就是指向最新提交对象的指针,默认指向master分支
-
git branch 分支名 这会在当前所在的提交对象上创建一个指针(创建一个新分支),但并不会自动切换到新分支上
-
git checkout 分支名 切换分支
-
git branch 不加任何参数,显示分支列表
-
git branch -d name 删除分支,但是不能在当前分支删自己 -D 强制删除
-
git branch -v 可以查看每一个分支的最后一次提交
-
git branch name commitHash 新建一个分支(name)并且使分支指向对应的提交对象(commitHash就是提交对象的hash值)
11. 分支实战
- 分支切换会改变你工作目录中的文件。
在切换分支时,一定要注意你工作目录里的文件会被改变。如果是切换到一个较旧的分支,你的工作目录会恢复到该分支最后一次提交时的样子。如果Git不能干净利落地完成这个任务,它将禁止切换分支
-
最佳实践:每次切换分支前,当前分支一定是已提交状态
-
坑:在切换分支时,如果当前分支上有未暂存的修改(第一次) 或者 有未提交的暂存(第一次),分支可以切换成功,但是这是这种操作可能会污染其他分支(文件会保留)
-
切换分支改变三个地方:HEAD ; 暂存区 ; 工作目录
-
git merge 分支名
-
快进合并,没有冲突
-
典型合并,有冲突
12. Git存储
- git stash 会将未完成的修改保存到一个栈上,可以在任何时候重新应用这些改动(git stash apply 不会删除)
- git stash list 查看存储
- git stash pop 应用存储然后立即从栈上扔掉它
13.Git 后悔药
- 工作区:如何撤回自己在工作目录中的修改
git checkout – filename
-
暂存区:如何撤回自己的暂存
git reset HEAD filename
-
版本库:如何撤回自己的提交
只能让用户重现修改注释
git commit --amend
14.Git后悔药 reset
-
git reflog : 只要是HEAD有变化,那么git reflog就会记录袭来
-
git reset --soft HEAD~ (–amend)
这个命令本质上是撤销了上一次git commit 命令。当你将它reset回HEAD~(HEAD的父结点)时,其实就是把该分支移动回原来的位置,而不会改变索引和工作目录。
只改变了HEAD,带着分支一起移动
-
git reset --mixed HEAD~ (mixed可以默认不写)
改变HEAD,带着分支一起移动
同时也改变了暂存区
-
git reset --hard HEAD~
改变了HEAD,带着分支一起移动
改变了暂存区,改变了工作目录
-
git checkout commitHash & git reset --hard commitHash 区别
1.checkout 只动HEAD, --hard 动HEAD而且带着分支一起走
2.checkout 对工作目录是安全的,会通过检查来确保不会将已更改的文件弄丢, --hard是强制覆盖工作目录
-
路径 reset
git reset [–mixed] [HEAD] filename (reset将会跳过第一步,不动HEAD)
只动暂存区
15. Git 完结
-
数据恢复: reflog,硬重置; 在找到的hash上新建分支
-
打tag:Git 可以给历史中的某一个提交打上标签,以示重要。比较有代表性的 是人们会使用这个功能来标记发布结点(v1.0等等)
-
git 使用两种主要类型的标签:轻量标签 和 附注标签
-
轻量标签很像一个不会改变的分支,他只是一个特定提交的引用
git tag v1.0 commitHash
-
-
查看特定标签 git show tagname
-
删除标签 git tag -d tagname
-
检出标签 git checkout tagname
但是这样会造成 detached head
应该在此创建新的分支 git checkout -b name
16. Git 复习
-
分支本质是一个提交对象,分支都会被HEAD所引用,当我们有新的提交时,HEAD会携带当前持有的分支往前移动
-
git branch 分支名
-
git checkout 分支名
-
git checkout -b 分支名 创建并切换
-
git branch -d/-D 分支名 删除分支
-
git merge 分支名 合并分支
快进合并、典型合并
-
git branch name commitHash 在某个提交对象创建分支
-
在切换分支的时候,一定要保证当前分支时干净的
分支上所有的内容已处于 已提交状态
(避免)分支上的内容是初始化创建,处于未跟踪状态
(避免)分支上的内容是初始化创建,第一次处于已暂存状态
-
git stash 会将当前分支上的工作推到一个栈中
-
git stash pop 取出栈顶并删除
-
git stash list 查看存储
-
撤销工作目录的修改 : git branch – filename
-
撤销暂存区的修改 : git reset HEAD filename
-
撤销提交: git commit --amend
-
git reset --soft commitHash 用commitHash的内容重置HEAD内容
-
git reset [–mixed] commitHash 重置HEAD,重置暂存区
-
git reset --hard commitHash 重置HEAD,重置暂存区,重置工作目录
-
git checkout 分支名 跟 git reset --hard commitHash 比较相似,都会重置HEAD,暂存区,工作目录
但是checkout 对工作目录是安全的,reset --hard 是强制覆盖的;checkout动HEAD时不会带着分支走,而是切换分支,reset --hard是带着分支走的
-
git checkout commitHash filename
- 重置暂存区
- 重置工作目录
-
git checkout – filename
- 重置工作目录
17.远程仓库
-
项目经理初始化远程仓库
-
项目经理创建本地仓库
- git init
- 将源码复制近来
- 修改用户名 修改邮箱
- git add git commit
-
项目经理为远程仓库配置别名 & 用户信息
- git remote add < shortname > < url > 添加一个新的远程Git仓库,同时指定一个简写
- git remote -v 显示远程仓库使用的Git别名 与其对应的URL
-
项目经理推送本地项目到远程仓库
初始化一个本地仓库后
- git push [remote-name] [branch-name]
- 推送完之后会附带生成远程跟踪分支
-
成员克隆远程仓库到本地
- git clone url (克隆时不需要git init)
- 默认克隆时为远程仓库起的别名为origin
- 只有在克隆的时候,本地分支master和 远程跟踪分支别名/master 是有同步关系的
-
项目经理邀请成员加入团队,在项目里的setting里要求collaborators
-
成员做出贡献
- 修改源码文件
- git add git commit
- git push 别名 分支 (输入用户名,密码,推完之后会生成远程跟踪分支)
-
项目经理更新成员提交的内容
- git fetch [remote-name] (将修改同步到远程跟踪分支上)
- git merge 远程跟踪分支
18.远程跟踪分支
-
远程分支
-
远程跟踪分支
远程跟踪分支时远程分支状态的引用。它们是你不能移动的本地分支。当你做任何网络通信操作时,它们会自动移动。
当克隆一个仓库时,它通常会自动地创建一个跟踪origin/master的 master分支
-
本地分支
正常的数据推送 和 拉取步骤
-
确保本地分支已经跟踪了远程跟踪分支
git branch -u origin/serverfix 设置已有的本地分支跟踪一个拉取下来的远程分支
-
拉取数据: git pull
-
上传数据: git push
-
-
一个本地分支 怎么去跟踪一个远程跟踪分支
1.当克隆的时候,会自动生成一个master本地分支(已经跟踪了对应的远程跟踪分支
2.在新建其他分支时,可以指定想要跟踪的远程跟踪分支
git checkout -b 本地分支名 远程跟踪分支名
git checkout --track 远程跟踪分支名
3.将一个已经存在的本地分支 改成一个跟踪分支
git branch -u 远程跟踪分支名
git branch -vv 查看本地分支跟踪的分支
19.解决冲突
-
git本地操作的冲突:典型合并
-
git 远程协作的时候的冲突
push 冲突时,先pull下来修改冲突部分,再push提交
pull 类似
-
删除远程分支
-
git push origin --delete 远程分支名
删除远程分支
-
git remote prune origin --dry-run
列出仍在远程跟踪但是远程已被删除的无用分支
-
git remote prune origin
清除上面命令列出来的远程跟踪
-
20.pull request
- 如果你想参与某个项目,但是并没有推送权限,这时可以对这个项目进行“派生”(Fork)。 派生的意思是指,GitHub将在你的空间中创建一个完全属于你的项目副本,且你对其具有推送权限。
21.总结
-
三个必须懂得的概念
- 本地分支
- 远程跟踪分支 (remote/分支名)
- 远程分支
-
远程协作的基本流程
- 项目经理创建一个空的远程仓库
- 项目经理创建一个待推送的本地仓库
- 为远程仓库配别名,配完用户名,邮箱
- 在本地仓库中初始化代码 ,提交代码
- 推送
- 邀请成员
- 成员克隆远程仓库
- 成员做出修改
- 成员推送自己的修改
- 项目经理拉取成员的修改
-
做跟踪
-
克隆仓库时,会自动为master做跟踪
-
本地没有分支
git checkout --track 远程跟踪分支
-
本地已经创建了分支
git branch -u 远程跟踪分支
-
-
推送 git push [别名] [分支名]
-
拉取 git pull
git fetch 别名 ; 合并远程跟踪分支
-
pull request
让第三方人员参与项目
-
.gitignore 忽略文件