git
对git的整体理解
是什么?
分布式版本控制软件,最初目的是为更好地管理Linux
内核开发而设计。分布式版本控制系统的客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。
项目开始,只有一个原始版仓库,别的机器可以clone
这个原始版本库,那么所有clone
的机器,它们的版本库其实都是一样的,并没有主次之分。所以在实现团队协作的时候,只要有一台电脑充当服务器的角色,其他每个人都从这个“服务器”仓库clone
一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交。github
实际就可以充当这个服务器角色,其是一个开源协作社区,提供Git
仓库托管服务,既可以让别人参与你的开源项目,也可以参与别人的开源项目。
工作原理
通过git init
创建或者git clone
一个项目的时候,项目目录会隐藏一个.git
子目录,其作用是用来跟踪管理版本库的。
当修改文件的时候,git
就会修改文件的状态,可以通过git status
进行查询,状态情况如下:
- 已修改(modified):表示修改了文件,但还没保存到数据库中。
- 已暂存(staged):表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。
- 已提交(committed):表示数据已经安全的保存在本地数据库中。
不同状态的文件在Git
中处于不同的工作区域,主要分成了四部分:
- 工作区:相当于本地写代码的区域,如 git clone 一个项目到本地,相当于本地克隆了远程仓库项目的一个副本
- 暂存区:暂存区是一个文件,保存了下次将提交的文件列表信息,一般在 Git 仓库目录中
- 本地仓库:提交更新,找到暂存区域的文件,将快照永久性存储到 Git 本地仓库
- 远程仓库:远程的仓库,如 github
常用命令
fork
- 代表分叉、克隆出一个(仓库的)新拷贝
- 包含了原来的仓库(即upstream repository,上游仓库)所有内容,如分支、Tag、提交
clone
- 将文件从远程代码仓下载到本地,从而形成一个本地代码仓
- 在这个目录下初始化一个
.git
文件夹
branch
- 开启另一个分支, 将当前工作从开发主线上分离开来,以免影响开发主线
config
设置控制
Git
外观和行为的配置变量git init 初始化仓库,默认为 master 分支
git add . 提交全部文件修改到缓存区
git add <具体某个文件路径+全名> 提交某些文件到缓存区
git diff 查看当前代码 add后,会 add 哪些内容
git diff –staged查看现在 commit 提交后,会提交哪些内容
git status 查看当前分支状态
git pull <远程仓库名> <远程分支名> 拉取远程仓库的分支与本地当前分支合并
git pull <远程仓库名> <远程分支名>:<本地分支名> 拉取远程仓库的分支与本地某个分支合并
git commit -m “<注释>” 提交代码到本地仓库,并写提交注释
git commit -v 提交时显示所有diff信息
git commit –amend [file1] [file2] 重做上一次commit,并包括指定文件的新变化
分支操作
- git branch 查看本地所有分支
- git branch -r 查看远程所有分支
- git branch -a 查看本地和远程所有分支
- git merge <分支名> 合并分支
- git merge –abort 合并分支出现冲突时,取消合并,一切回到合并前的状态
- git branch <新分支名> 基于当前分支,新建一个分支
- git checkout –orphan <新分支名> 新建一个空分支(会保留之前分支的所有文件)
- git branch -D <分支名> 删除本地某个分支
- git push <远程库名> :<分支名> 删除远程某个分支
- git branch <新分支名称> <提交ID> 从提交历史恢复某个删掉的某个分支
- git branch -m <原分支名> <新分支名> 分支更名
- git checkout <分支名> 切换到本地某个分支
- git checkout <远程库名>/<分支名> 切换到线上某个分支
- git checkout -b <新分支名> 把基于当前分支新建分支,并切换为这个分支
远程同步
- git fetch [remote] 下载远程仓库的所有变动
- git remote -v 显示所有远程仓库
- git pull [remote] [branch] 拉取远程仓库的分支与本地当前分支合并
- git fetch 获取线上最新版信息记录,不合并
- git push [remote] [branch] 上传本地指定分支到远程仓库
- git push [remote] –force 强行推送当前分支到远程仓库,即使有冲突
- git push [remote] –all 推送所有分支到远程仓库
撤销
- git checkout [file] 恢复暂存区的指定文件到工作区
- git checkout [commit] [file] 恢复某个commit的指定文件到暂存区和工作区
- git checkout . 恢复暂存区的所有文件到工作区
- git reset [commit] 重置当前分支的指针为指定commit,同时重置暂存区,但工作区不变
- git reset –hard 重置暂存区与工作区,与上一次commit保持一致
- git reset [file] 重置暂存区的指定文件,与上一次commit保持一致,但工作区不变
- git revert [commit] 后者的所有变化都将被前者抵消,并且应用到当前分支
存储
正在进行项目中某一部分工作,里面的东西处于一个比较杂乱的状态,但是想转到其他分支上进行一些工作,但又不想提交这些杂乱的代码,这时候可以将代码进行存储
- git stash 暂时将未提交的变化移除
- git stash save 用于存储修改,并将git工作状态切回到HEAD,也就是上一次合法提交上
- git stash pop 取出存储中最后存入的工作状态进行恢复,会删除存储
- git stash list 查看所有存储中的工作
- git stash apply <存储的名称> 取出存储中对应的工作状态进行恢复,不会删除存储
- git stash show 查看堆栈中最新保存的stash和当前目录的差异
- git stash clear 清空所有存储中的工作
- git stash drop <存储的名称> 删除对应的某个存储
开发到一半,但还不想提交,并且当前本地代码和远程代码可能存在冲突时,使用git pull需要合并冲突。这个时候可以使用git stash、git pull、git stash pop。
HEAD
在git
中存在很多分支,其本质上是一个指向commit
对象的可变指针,而Head
是一个特别的指针,是一个指向你正在工作中的本地分支的指针。
当切换分支的时候,HEAD
指针通常指向当前所在分支,当在某个分支上创建新的提交时,分支指针总是会指向当前分支的最新提交。
所以,HEAD指针 ——–> 分支指针 ——–> 最新提交
工作树和索引
工作树实际就是指工作区。在数据库和工作树之间有索引,索引是为了向数据库提交作准备的区域,也被称为暂存区域。Git
在执行提交的时候,不是直接将工作树的状态保存到数据库,而是将设置在中间索引区域的状态保存到数据库。因此,要提交文件,首先需要把文件加入到索引区域中。所以,凭借中间的索引,可以避免工作树中不必要的文件提交,还可以将文件修改内容的一部分加入索引区域并提交。
fetch与pull的区别
git fetch
是将远程主机的最新内容拉到本地,用户在检查了以后决定是否合并到本机分支中。
git pull
则是将远程主机的最新内容拉下来后直接合并,即:git pull = git fetch + git merge
,这样可能会产生冲突,需要手动解决。
git merge与git rebase
git rebase
与 git merge
都有相同的作用,都是将一个分支的提交合并到另一分支上,但是在原理上却不相同。
git merge
git rebase
区别
- git merge:通过
merge
合并分支会新增一个merge commit
,然后将两个分支的历史联系起来。其实是一种非破坏性的操作,对现有分支不会以任何方式被更改,但是会导致历史记录相对复杂。 - git rebase:
rebase
会将整个分支移动到另一个分支上,有效地整合了所有分支上的提交。主要的好处是历史记录更加清晰,是在原有提交的基础上将差异内容反映进去,消除了git merge
所需的不必要的合并提交。
冲突
发生冲突的场景
- 多个分支代码合并到一个分支
- 多个分支向同一个远端分支推送
具体情况就是,多个分支修改了同一个文件(任何地方)或者多个分支修改了同一个文件的名称。
解决冲突
当Git
无法自动合并分支时,就必须首先解决冲突,解决冲突后,再提交,合并完成。解决冲突就是把Git
合并失败的文件手动编辑为我们希望的内容,再提交。
git reset 与 git revert
是什么?
git reset用于回退版本,可以遗弃不再使用的提交。执行遗弃时,需要根据影响的范围而指定不同的参数,可以指定是否复原索引或工作树内容。
git revert在当前提交后面,新增一次提交,抵消掉上一次提交导致的所有变化,不会改变过去的历史,主要是用于安全地取消过去发布的提交。