Git基础配置
查看Git配置
git config --list --[ local | global | system ]
loccal global system 对应git中从小到大3个域,分别对应 本地 | 全局 | 全系统
信息保存位置:
- 本地信息:.git/config
- 全局信息:~/.gitconfig
优先级:
- 就近原则:本地信息级别优先于全局信息,二者都有时采用项目级别的签名
- 如果只有全局信息,就以全局信息为准
- 二者都没有,不允许
配置Git基本信息
git config --global user.name ‘networkcavalry ‘
git config --global user.email ‘networkcavalry@gmail.com‘
Git工作原理
- 工作区:.git隐藏目录加所在的目录即为工作区,一般为项目目录
- 暂存区:用于临时存储的区域(git add提交的区域)
- 版本库:用于保存和管理项目版本的区域
注意:.git隐藏目录是git的本地库,git就是依赖这个目录来完成对项目的管理,切记千万不要删除.git目录中的任何东西。git可以管理.git所在目录的所有文件以及嵌套的子文件等。无法管理.git所在目录之外的目录
Git本地常用操作
创建Git本地仓库
1.对已有项目代码加入Git管理
cd 项目代码所在文件夹
git init
2.新建项目直接使用Git
git init
创建后需要使用 cd 命令进入该项目的文件夹中
3.从已有的代码仓库中克隆到本地
- SSH的方式(推荐使用)
git clone git@github.com:networkcv/gittest.git
- Http的方式
git clone https://github.com/networkcv/gittest.git
4.克隆裸仓到本地
裸仓是指不克隆工作区,只克隆 .git文件,通常裸仓的命名都是以.git 结尾的,Github中给我们提供的也都是裸仓。
裸仓只能进行 push 和 pull,不能执行其他的git指令。
从本地另外一个地方克隆裸仓
git clone --bare file:///c/Users/Administrator/Desktop/gittest/gittest/.git
从远端仓库克隆裸仓
git clone --bare git@github.com:networkcv/gittest.git
提交到Git本地仓库
1.将变更文件加入暂存区
- 未加入Git版本追踪的情况
git status
我们可以使用这个命令来查看当前仓库所有文件的变更状态
1 | $ git status |
- 将单个文件加入git版本追踪
git add a.txt
- 将所有文件加入git版本追踪
git add -A
- 将已被git追踪的变更文件加入暂存区
git add -u
- 加入版本追踪后
1 | $ git status |
上例我们使用 git add
命令将文件加入git的版本控制当中,这只是它功能的一部分,该命令实际是将 工作区 已跟踪和未跟踪文件的更改添加到 暂存区中。
我们平时对文件的修改会自动保存到工作区中,然后我们再将工作区的内容保存到暂存区中,也就是我们刚才的操作,接下来需要将暂存区中的更改提交到本地仓库。
2.加入暂存区后就可以提交到本地仓库了
- 输入提交消息,描述此次提交是做了什么
git commit -m ‘git add test’
- 每次都要先保存到暂存区再提交太麻烦了,
commit
命令后加上-a
参数可以帮我们省略这一步
git commit -a
1 | $ git commit -am 'git add test' |
- 查看提交的记录
git log
1 | $ git log |
修改删除文件
- 删除文件
git rm a.txt
- 修改文件名
mv a.txt b.txt
git add b.txt
git rm a.txt
上面这种方式需要写三条git命令,比较繁琐。git为我们提供了更便捷的命令
git mv a.txt b.txt
查看历史版本
- 查看历史版本(默认当前所在分支)
git log
- 查看历史版本的简要信息
git log --oneline
1 | $ git log --oneline |
- 查看最新的两条简要信息
git log -n2 --oneline
1 | $ git log -n2 --oneline |
- 查看指定分支的历史版本
git log
- 查看所有分支的信息
git log --all
- 图形化查看分支继承 信息
git log --all --graph
- 通过GUI查看分支信息
gitk --all
修改commit的message
该操作建议在未push到远端的本地commit中使用,以下两种方式本质上是对commit进行变基。变基对本地的commit没有影响,而对远端的commit进行变基时,其他人可能已经拉取了旧的commit,这样等其他人再拉取变基后的commit时,则对方会在本地进行merge,如果其想保持本地单分支的话可以在merge后进行rebase,将分支合并到主干上。
由于这套组合操作比较常用,IDEA的git图形界面则在拉取时就提供了rebase的选型,这样就拉倒本地merge后就会自动合并了到主干了。
- 修改最近一次commit的message
git commit –amend
- 修改之前的commit的message
1 | $ git log -n3 --pretty=oneline |
比如我们要修改中间那次commit的message,由于rebase是变基,所以要选择它的下边的”地基“,也就是它的前一次commit,我们使用 git rebase -i/--interactive(交互) 版本号
这个命令。
$ git rebase -i dc6dff7515c28219711d7c4e0e1c837892664421
执行命令后,会进入交互式的操作中,会打开你本地的文本编辑器来进行rebase。
1 | // pick d07b359 git add 'd' 这个commit就是我们此次要修改的目标,这行实际是要删掉的 |
关闭上面的文件后,会重新弹出一个文本编辑界面,这里我们可以写修改后的message,修改完保存关闭就ok了。
查看修改后的结果。
1 | $ git log -n3 --pretty=oneline |
合并多个commit
这个操作也是通过 rebase
这个指令,同样对前一次的commit进行操作。
- 合并多个连续的commit成一个commit
git rebase -i b584c15c7b658fb6c4a3427eb567ab2fedf659d4
1 | // 将三次commit合并到最后一次 |
- 合并多个不连续的commit成一个commit
比如将 496ecae9e9
和 dc6dff7515
合并成一个commit
1 | $ git log --pretty=oneline -n3 |
$ git rebase -i b584c15c7b658fb6c4a3427eb567ab2fedf659d4
1 | pick dc6dff7 git add 'c' |
- 完成间隔commmit的合并
git rebase --continue
- 如果发生错误,使用该命令可以回到合并之前
git rebase --abort
查看内容变更
- 工作区比暂存区多出了哪些变化
git diff
- 只看该文件 ,注意
--
和文件名中间有空格
git diff -- 文件名
- 比较暂存区和head之间的变化
git diff --cached
- 比较两个版本的变化,新的放后边
git diff 403f3fc02c6 d659e047fdfa
- 只关注两个版本中某个文件的变化
git diff 403f3fc02c6 d659e047fdfa -- a.txt
- 比较当前Head和Head的父亲的变化
git diff head head~1
撤销相关操作
- 将暂存区的操作撤销回工作区
git reset
- 撤销工作区和工作区的所有操作
git reset --hard
- 删除该版本号之后的所有commit
git reset --hard 版本号
- 将暂存区的操作撤销回工作区 ,并将暂存区恢复到head版本
git reset head
- 将暂存区某个文件的操作撤销回工作区 ,并将暂存区中的该文件恢复到head版本
git reset head -- fileName
- 放弃工作区内的修改,恢复到暂存区的对应的文件
git checkout -- fileName
实际工作中,暂存区用到的还是比较少的,我们进行了操作后直接就从工作区提交到commit中,像内容比对这类操作都是针对commit来做的,弱化了暂存区的功能。在IDEA中可以设置,将所有对工作区的操作自动保存到暂存区中。
暂存未提交的修改
把未提交的修改临时保存起来,同时将工作区和暂存区恢复清空。等到方便的时候,再将这些内容进行恢复,继续之前的工作。
- 将当前所做操作临时保存
git stash
- 查看临时保存的集合
git stash list
- 只取出list中最后保存的,不删除,也可以指定某一个
git stash apply
- 取出并删除list中的最后保存的,也可以指定某一个
git stash pop
分支相关操作
- 查看分支
git branch
- 显示分支的详细信息
git branch -v |--verbose
- 列出远程跟踪和本地分支
git branch -a |--all
- 切换分支
git checkout 分支名
- 删除分支
git branch -D 分支名
- 从指定版本或分支创建一个新分支
git checkout -b 新分支名 版本号|已有分支名
1 | $ git checkout -b temp master |
- 将当前分支与该分支合并
git merge branchName
- 将两个无关的分支进行合并
git merge –allow-unrelated-histories origin/master
分离头指针开发
- detached head 分离头指针,相当于创建了一个临时分支来使用,切回主分支后需要手动保存,不然会被git清除,具体操作如下:
git checkout 版本号
1 | $ git checkout 4813a70f369340d6ac18bb719dd05c1575788fb |
- 查看一下分离头指针后的分支状态
1 | $ git branch |
1 | $ git status |
- 当我们需要切回master,git会提醒你临时的branch如果以后还想使用,则需要尽快对其建立新的分支
1 | $ git checkout master |
- 对刚才的临时分支建立新的分支
git branch
bc8be3e
Git远端常用操作
前面我们讲了git在本地的各种操作,单人开发中遇到的各个场景,而在实际工作中,一定是多人合作开发,这就涉及到对远端代码的推送和拉取操作了。
常见的传输协议
直观区别:哑协议传输进度不可见,智能传输协议可见。
传输速度:智能协议比哑协议传输速度快。
如果我们在执行些复杂且有危险性指令的时候,我们可以先将其备份到远端仓库,这里的远端仓库既可以是服务器上的仓库,也可以是本地其他位置的仓库。
路由相关操作
- 查看路由信息
git remote -v
- 添加路由信息
git remote add local file://c/Users/Administrator/bk/gittest.git
git remote add origin git@github.com:networkcv/gittest.git
拉取合并远端相关操作
- 只从远端拉取对应的分支,不进行其他操作
git fetch origin master
- 将指定分支与当前分支进行合并
git merge origin/master
- 如果远端的分支和本地的分支完全没有关联,是两个不相干的树,也可以进行合并
git merge --allow-unrelated-histories orgin/master
合并完成后可能会出现下面这样的情况。
我们来详细分析一下,最初的commit的是 git rebase all,本地在此基础上增加了 add f 这个commit,而远端的 Create c.txt 可能是其他同事同样基于 git rebase all 这个commit进行的修改,并且推送到了远端的代码仓库,可以看到 remotes/origin/master 指向他新提交的commit。
在我们执行 fetch 操作后,只会将本地分支中远端master的指向ref同步,并不会将该ref指向的对象同步到本地,只有执行merge时,才会将ref指向的对象同步到本地的 .git 文件中。
在发生merge后,会生成一个新的commit,这个commit中会有两个 parent,分别是 Create c.txt 和 add f 对应的版本号,这是因为Create c.txt 中的tree有指向 c.txt的这个blog,而add f 完全没有和 c.txt相关的信息,它里边只有关于 add f 的修改。因此只有将两份commit拼凑在一起才是完整的仓库状态,但也因此会出现分叉。
如果我们想消除这种分叉,使版本以一条直线的方式来进行变更,这样可以更好的去观察版本之间的变化。我们可以使用之前有提到的 git reabse -i 命令来进行变基。在变基中,其实就是选取了两个commit中的一个来做外另外一个的parent,被选为parent的commit不用做什么变更,假设 add f 这个commit作为parent,Create c.txt 作为children,而作为Children的commit需要做一些变动。
- 将其parent的指向从原来的git rebase all 修改为 add f
- 将parent的tree中的内容复制到children的tree中,如果遇到了共同修改的文件,则会发生冲突,需要我们手动的去解决,将两边的变更点进行整合和取舍然后保存到children的tree中
这样就完成了变基。
直接使用 pull
pull命令其实就是先fetch然后再merge。merge之后我们也可以进行rebase使其版本变化显示为一条直线。
其他
探秘.Git目录
HEAD 中的内容是指向当前工作分支的头部
config 存放的是 用户 local 的配置
refs 中存放的是分支(heads)和标签(tags)的引用
objects 中存放的是上边那些引用真正指向的位置,文件的每次变更都会存在这里。
objects 中的文件如下:
1 | $ ll |
每个commit都会对应一个tree,在tree中记录了这次提交时整个项目的快照,tree中可以包含blob也可以包含其他的tree
而 objects 中存放的就是这些tree,为了方便查找,git 将按照tree名称的前两个字母进行分类,如上图所示,进入除了 info/ 和 pack/ 之外的文件夹中,看到的就是去掉前两个字母的tree名称,下例中该tree的完整名称是 dab7902aa19375da590c0349bbc0a126e240f4d7
,一定要注意加上文件夹名称才是完整的tree名
1 | Administrator@NetworkCavalry MINGW64 ~/Desktop/gittest/gittest/.git/objects/da (GIT_DIR!) |
可以通过下面的命令来查看objects文件夹中对象 的内容或类型
- 查看类型
git cat-file -t tree_name
1 | $ git cat-file -t dab7902aa19375da590c0349bbc0a126e240f4d7 |
- 查看内容
git cat-file -p tree_name
1 | $ git cat-file -p dab7902aa1 |
Git的commit、tree、blob对象
- 每次提交都会创建一个commit对象,包含tree、parent、author、committer对象信息
- tree对象为可以理解为文件夹,文件夹中包含文件(blob)或文件夹(tree)
- blob对象为文件对象,git中将相同内容的文件看作同一个blob对象