版本控制
集中式(svn)
- svn 因为每次存的都是差异,需要的硬盘空间会相对的小一点,但回滚的速度会很慢
- 优点: 代码存放在单一的服务器上 便于项目的管理
- 缺点: 服务器宕机,数据就存在丢失的风险
分布式(git)
- git 每次存的都是项目的完整
快照
,需要的硬盘空间会相对大一点
(Git 团队对代码做了极致的压缩,最终需要的实际空间比 svn 多一点,但回滚速度极快) - 优点: 完全的分布式
- 缺点: 学习起来比 SVN 陡峭
- git 每次存的都是项目的完整
底层命令
git 对象
- 生成一个 hash 值:压缩后的文件内容的键值对存到.git/objects:git hash-object -w fileUrl
tree 对象
- 往暂存区添加一条记录(让 git 对象对应上文件名)存到.git/index:git update-index –add –cacheinfo 100644 hash test.txt
- 生成树对象存到.git/objects: git write-tree
commit 对象
- 生成一个提交对象存到.git/objects: echo ‘first commit’ | git commit-tree treehash
初始化配置和文件的 UDR 命令
初始化配置
- 配置用户名:git config –global user.name “name”
- 配置邮箱:git config –global user.email name@example.com
- 获取设置配置列表:git config –list
- 初始化仓库: git init
U(修改提交操作)
- 将单个文件从工作区添加到暂存区:
git add <file>
- 将所有文件添加到暂存区:
git add .
- 将暂存区的文件提交到本地仓库:
git commit -m "msg"
- 将单个文件从工作区添加到暂存区:
D(删除 & 重命名)
- 删除:
git rm 要删除的文件
- 重命名:
git mv 老文件名 新文件民
- 删除:
R(查询操作)
- 查看工作目录中文件的状态:
git status
(已跟踪(已提交 已暂存 已修改) 未跟踪) - 查看未暂存的修改,比较文件不同,即暂存区和工作区的差异:
git diff
- 查看未提交的暂存:
git diff --cache
- 查看提交记录:
git log --oneline
- 查看工作目录中文件的状态:
分支
分支的本质其实就是一个提交对象!!!
HEAD:
- 一个指针,它默认指向 master 分支,切换分支时其实就是让 HEAD 指向不同的分支
- 每次有新的提交时 HEAD 都会带着当前指向的分支,一起往前移动
git 分支命令
- 查看整个项目的分支图:
git log [--oneline | --decorate | --graph | --all]
- 查看整个项目的分支图:
查看分支
- 查看分支列表:
git branch
- 查看所有分支:
git branch -a
- 查看分支指向的最新的提交:
git branch -v
- 查看合并到当前分支的分支列表:
git branch --merged
(一旦出现在这个列表中就应该考虑删除已合并的分支) - 查看没有合并到当前分支的分支列表:
git branch --no-merged
(一旦出现在这个列表中就应该观察一下是否需要合并)
- 查看分支列表:
创建分支
- ⭐ 创建分支:
git branch <name>
- 在指定的提交对象上创建新的分支:
git branch <name> commithash
— 版本穿梭(时光机)
- ⭐ 创建分支:
删除分支
- ⭐ 删除本地分支:
git branch -d <name>
- 强制删除分支:
git branch -D <name>
- ⭐ 删除远程分支:
git push origin -d <name>
- ⭐ 删除本地分支:
切换分支
- ⭐ 切换分支:
git checkout <name>
- 创建并切换到新分支:
git checkout -b <name>
- ⭐ 切换分支:
合并分支
- 合并某个分支到当前分支,默认 fast forward:
git merge <name>
- 快进合并 –> 不会产生冲突
- 典型合并 –> 有机会产生冲突
- 解决冲突 –> 打开冲突的文件 进行修改 add commit
- 合并某个分支到当前分支,默认 fast forward:
git 分支的注意点
- 在切换的时候 一定要保证当前分支是干净的!!!
- 允许切换分支:
- 分支上所有的内容处于已提交状态
- (避免)分支上的内容是初始化创建 处于未跟踪状态
- (避免)分支上的内容是初始化创建 第一次处于已暂存状态
- 不允许切分支:
- 分支上所有的内容处于已修改状态或第二次以后的已暂存状态
- 在分支上的工作做到一半时 如果有切换分支的需求, 我们应该将现有的工作贮藏起来
贮藏
- ⭐ 将当前工作区改过的文件贮藏到栈中,贮藏后当前库是上一个已提交的状态: git stash
- ⭐ 查看当前贮藏列表的文件:
git stash list
- 将栈顶的工作内容恢复,但不让任何内容出栈:
git stash apply <name>
- 取出栈顶的工作内容后就应该将其删除(出栈):
git stash drop
- ⭐ 恢复贮藏起来的文件并把列表中对应文件删除,是 apply+drop 操作:
git stash pop <name>
撤销与回退操作(后悔药)
撤销:当修改了工作区/暂存区的文件,想要撤销之前的操作
场景 1:(撤销工作目录的修改)当改乱了工作区某个文件的内容,但还未 add 到暂存区
- 撤销指定文件的修改:
git checkout -- 文件名
(--
表示是文件名不是分支名,不混淆可不用) - 撤销所有工作区的修改:
git checkout .
- 撤销工作区和暂存区的所有修改:
git checkout -f
- 撤销指定文件的修改:
场景 2:(撤销暂存区的修改)当乱改了工作区某个文件的内容,并且 git add 到了暂存区
- 第 1 步,将暂存区的文件修改撤销掉:
git reset HEAD <file>
- 第 2 步,将工作区的文件修改撤销掉:
git checkout <file>
- 第 1 步,将暂存区的文件修改撤销掉:
场景 3:乱改了很多文件,想回到最新一次提交时的状态
- 撤销工作区中所有未提交文件的修改内容:
git reset --hard HEAD
- 撤销工作区中所有未提交文件的修改内容:
场景 4:(撤销提交)在当前最后一次提交的 commit 信息,还没有 push 到远程
git commit --amend
回退:当已经进行了 commit 操作,需要回退到之前的版本:
- 查看每一步操作的记录:
git reflog
(谨慎!!!每次改变都会记录) - 设置为某一 id 的记录:
git reset id
- 设置为对应 id 记录:
git reset --hard id
- 回退到上次提交的状态:
git reset --hard HEAD^
- 回退到 n 个版本前的状态:
git reset --hard HEAD~n
- 回退到某一个 commitid 的状态及内容,只改变 HEAD:
git reset --soft HEAD commitid
- 回退到某一个 commitid 的状态,并保留工作区的内容:
git reset --mixed(默认) HEAD commitid
- 回退到某一个 commitid 的状态及内容,并重置暂存区和工作目录:
git reset --hard HEAD commitid
checkout 深入
- git checkout brancname 跟 git reset –hard commithash 特别像
共同点
- 都需要重置 HEAD 暂存区 工作目录
区别
- checkout 对工作目录是安全的 reset –hard 是强制覆盖
- checkout 动 HEAD 时不会带着分支走而是切换分支
- reset –hard 时是带着分支走
checkout + 路径
- git checkout commithash filename
- 重置暂存区
- 重置工作目录
- git checkout – filename
- 重置工作目录
远程协作
基本流程
项目经理初始化远程仓库
- 一定要初始化一个空的仓库; 在 github 上操作
项目经理创建本地仓库
- git remote 别名 仓库地址(https)
- git init 将源码复制进来
- 修改用户名 修改邮箱
- git add
- git commit
项目经理推送本地仓库到远程仓库
- 清理 windows 凭据
- git push 别名 分支 (输入用户名密码;推完之后会附带生成远程跟踪分支)
项目邀请成员 & 成员接受邀请
- 在 github 上操作
成员克隆远程仓库
- git clone 仓库地址 (在本地生成.git 文件 默认为远程仓库配了别名 orgin)
- 只有在克隆的时候 本地分支 master 和 远程跟踪分支别名/master 是有同步关系的
成员做出贡献
- 修改源码文件
- git add .
- git commit
- git push 别名 分支 (输入用户名 密码;推完之后会附带生成远程跟踪分支)
项目经理更新修改
- git fetch 别名 (将修改同步到远程跟踪分支上)
- git merge 远程跟踪分支
做远程跟踪
- 克隆仓库时会自动为 master 做跟踪
- 本地没有分支:
git checkout --track remote/分支名
- 本地已经创建了分支:
git branch -u remote/分支名
远程操作
- 刷新远程分支信息:
git fetch
- 将本地 master 分支推送到远程对应分支:
git push origin master
- 下载远程代码并合并:
git pull
- 拉取远程最新代码并合并,不会产生 Merge:
git pull --rebase
- 推送本地代码到远程分支上:
git push
- 将远程仓库和本地仓库关联起来:
git remote add origin <url>
- 查看远程库信息:
git remote -v
rebase 和 merge
rebase: 把分叉的提交历史“整理”成一条直线,看上去更直观
- 变基:
git rebase
- 将当前分支移植到指定分支或者 commit 之上:
git rebase -i <commit>
- 从远程回退到未提交状态:
git reset HEAD^
- 变基:
merge: 每次操作都会产生一条 merge 记录,从日志上看的,会产生分叉,日志看起来杂乱
git 修改默认 pull 的参数
- git pull = git fetch + git merge
- 全局修改 pull 的命令:
git config --global --add pull.rebase true
- 查看命令是否修改成功:
git config --global -l
- 如果之前向全局配置文件修改过 pull 的配置项,但修改错了,使用
--unset
- 使用–unset 后,发现提示有多个值,则使用
--replace-all
- 示例: git config –global –replace-all pull.rebase true
修改全局配置项
新增一个配置项:
--add
- 格式:
git config --local/--global/--system --add section.key value
- 示例: git config –global –add pull.rebase true
- 格式:
获取一个配置项:
--get
- 格式:
git config --local/--global/--system --get section.key
- 格式:
删除一个配置项:
--unset
- 格式:
git config --local/--global/--system --unset section.key
- 示例:git config –global –unset pull.rebase
- 格式:
查看配置文件:
--list/-l
- 查看仓库级的 config:
git config --local -l
- 查看全局级的 config:
git config --global -l
- 查看系统级的 config:
git config --system -l
- 查看当前生效的配置:
git config -l
- 查看仓库级的 config:
编辑配置文件:
--edit/-e
- 编辑仓库级的 config:
git config --local -e
- 编辑全局级的 config:
git config --global -e
- 编辑系统级的 config:
git config --system -e
- 编辑仓库级的 config:
基本概念
- 本地仓库:本地仓库上存放所有相关的文件,具体可分为工作区、暂存区和仓库区,工作区即项目文件夹下不包含.git 文件夹的所有文件,暂存区和仓库区则在.git文件夹下
- 工作区:即我们工作的文件夹,在里面进行文件的增删改操作
- 暂存区:临时保存工作区上的改动,通过
git add
操作将工作区的修改同步到暂存区
- 仓库区:当执行
git commit
操作时,将暂存区上的所有变动同步到本地仓库
- 远程仓库:GitHub/GitLab 上保存的仓库,通过 git push 将本地仓库同步到远程仓库,也可以通过 git fetch/pull 将远程仓库同步到本地仓库
- 快照:git 将顶级目录中的文件和文件夹称作集合,并通过一系列快照来管理历史记录。在 git 的术语中,文件被称为blob对象(数据对象),也就是一组数据。目录则被称为tree(树)>,目录可以包含文件和子目录。快照统称“commit”>,每个快照都有一系列的父辈。每次commit都是创建一个全新的记录
- master 引用通常会指向主分支的最新一次 commit.在 Git 中,当前的位置有一个特殊的索引,它就是“HEAD”。
checkout 可以用于切换分支,可以从历史提交或暂存区中拷贝文件到工作目录
- 当给定某个文件名时,git 会从指定的提交中拷贝文件到暂存区域和工作目录。
HEAD 标识处于分离状态的提交操作
- 可以正常提交,但不会更新任何命名分支,一旦切换到别的分支,这个提交节点再也不会被引用就会被丢弃
- 如果想保存这个状态,可以用 git checkout -b name 来创建一个新的分支
Reset
- 也用来从仓库中复制文件到索引,而不动工作目录
- 如果不给选项,那么当前分支指向到那个提交。如果用–hard 选项,那么工作目录也更新,如果用–soft 选项,都不变
- 如果没有给出提交点的版本号,那么默认用 HEAD。分支执行不变,但是索引会回滚到最后一次提交。如果用–hard 选项,工作目录也同样
Merge
- merge 命令把不同分支合并起来。合并前,索引必须和当前提交相同。
- cherry-pick 复制一个提交节点并在当前分支做一次完全一样的新提交
Rebase
- 合并分支。本质上,是线性化的自动的 cherry-pick
工作原理
1 | graph TB |
- 查看每个 SHA-1 的类型:
git cat-file -t
- 查看每个对象的内容和简单的数据结构:
git cat-file -p
- 把当前文件放入暂存区:
git add files
- 把暂存区生成快照并提交本地仓库:
git commit
- ⭐ 用来
撤销暂存区
的某一文件, git reset 撤销所有暂存区的文件:git reset -- files
- 把文件从暂存区复制到仓库区,用来丢弃本地修改:
git checkout -- files
- 回滚到复制最后一次提交:
git checkout HEAD -- files
- 相当于运行 git add 把工作区的所有文件加入暂存区再提交到仓库区:
git commit -a
- 进行最后一次提交+工作目录中文件快照的提交,并且文件被添加到暂存区:
git commit files
- 比较两次提交记录的差异:
git diff commitId commitId
- 比较跟远程分支的差异:
git diff HEAD
- 比较跟暂存区的记录的差异:
git diff
- 比较跟某一分支记录的差异:
git diff 分支名
- 使用与当前提交相同的父节点进行一次新提交,旧的提交会被取消:
git commit --amend