文章目录
1. commit object与分支
每个 commit object 代表了这个项目的所有代码在那次提交的时候一个完整的快照版本,包含了之前没有变更的代码文件,也包括了这次提交的最新的修改/新增/删除的代码文件。
1.1 commit object
git 并不是存储一系列的文件差异,而是存储一系列的文件快照的。
每次执行一次 commit,git 都会存储一个 commit object,这个 commit object 中会包含一个指针,指向这次提交文件的快照。这个 commit object 同时也包含作者的姓名和邮箱,提交说明,以及对上一次 commit object 的指针
将一个文件版本放入暂存区的时候,就会计算一个校验和,然后提交的时候会将文件内容以 blob 的方式放入版本库中,同时在暂存区放入这个文件版本的校验和。接着 git 会创建一个 commit object,其中会包含元数据,以及一个指针指向版本库中的文件快照。
也就是说,每次执行一次提交,都会在版本库中包含如下内容:
- 一个 blob,每个文件都会有一个 blob 来存储这个文件的本次提交的快照
- 一个 tree,这个 tree 会包含对本次提交的所有文件的 blob 的指针
- 一个 commt object,指向了 tree 的指针,作者,等信息。如果不是第一次提交,这个 commit object 同时还会有一个指针,指向上一个 commit object
进行多次提交后,就会得到一个完整的 commit 树。
1.2 分支
在 git 中,分支就是指针,它指向了提交历史中的某个 commit object。
默认的分支是 master,每次提交时,master 分支的指针默认就是指向最新的那个 commit object。每次提交一次,master 指针就会挪动,继续指向最新的 commit object。
如果当前工作在在 master 分支上,那么 git 还维护了一个特殊的指针——HEAD 指针。这个指针指向 master 分支指针。如果还创建了其他的分支,那么其他的分支也会指向某个 commit object,而且此时如果工作在那个分支上,那么 HEAD 指针会指向该分支。
2.实战模拟
2.1 环境准备
复制一份 git_in_action,模拟2人在开发维护一个项目
2.2 创建分支
- git branch 分支名
- git checkout -b 分支名
下面的命令在创建分支的同时也切换到这个分支上去。比如在master分支上执行了 git checkout -b feature/01
,此时会创建一个新的分支对应的指针 feature/01,它指向了 master 当前指向的那个 commit object
git checkout feature/01
,此时就可以切换到 feature/01 分支,HEAD 指针会指向 feature/01 分支指针。
此时如果在 feature/01 分支上提交代码,那么 commit 树会长出来一个新的 commit object,而 feature/01 分支指针会指向最新的 commit object,HEAD 继续指向 feature/01 分支指针,而 master 指针还是指向之前的那个 commit object。
张三创建并切换分支:
李四创建并切换分支:
2.3 切换分支
git checkout 分支名
2.4 查看分支
-
git branch
显示出当前所有分支列表,以及你在哪个分支上工作
-
git branch -v
显示出每个分支当前指向的 commit object
-
git branch --merged
可以看到哪些分支被merge到了当前分支
-
git branch --no-merged
可以看到哪些分支没有被 merge 到了当前分支
2.5 查看分支指向的commit object
git log --oneline --decorate
2.6 删除分支
git branch -d 分支名:如果你有一个分支,还没有合并到 master 分支去,此时 git 不让你删除的
git branch -D 分支名:强制删除一个没有合并到别的分支的分支
2.6 远程分支
2.6.1 在码云上新建项目(仓库)
2.6.2 添加公钥
-
本地创建公钥
ssh-keygen -t rsa -C "xxx@163.com" # Generating public/private rsa key pair... # 三次回车即可生成 ssh key
-
查看公钥
cat ~/.ssh/id_rsa.pub ssh-rsa AAA...PFp xxx@163.com
-
添加到码云
-
检查是否添加成功
ssh -T git@gitee.com
第一次绑定的时候输入上边的代码之后会提示是否 continue,输入 yes 后程序会自动连接。
如果要求登录,直接输入登录信息即可。
2.6.4 推送本地分支到远程仓库
李四正要推送本地 ls/001分支
到远程仓库
-
关联远程仓库
git remote add origin https://gitee.com/xxx/gitDemo.git
关联后,对要推送的分支执行 add、commit 命令
-
拉取远程仓库文件合并
git pull origin master --allow-unrelated-histories
第一次拉取时,需要输入用户名和密码 -
推送到远程仓库
git push -u origin master
第一次,需要使用 -u
将本地分支和远程分支关联起来。当前推送时存在冲突
git checkout master
.gitignore: needs merge
error: you need to resolve your current index first
编辑冲突文件
vi .gitignore
解决冲突
推送到远程
git add --all .
git commit -m "解决冲突"
git push -u origin master
2.6.5 抓取远程分支新增的分支
git fetch origin
该命令会将远程版本库的 commit 树和所有的分支都拉取下来,跟本地的 commit 树进行合并,此时可能就会在本地形成一棵有两个分叉的 commit 树。
2.6.6 解决git pull/push 免密码
vim .git/config
将图片中的HTTPS地址改为SSH地址
url = git@gitee.com:xxx/gitDemo.git
3.冲突问题的产生
在拉取了两个分支 A、B 并行开发
git checkout -b A
git checkout -b B
假设 A 分支的开发者张三先对第 10 行进行了修改并且合并到了 master 上。
System.out.println(“I like spark......”);
接着 B 分支也对第10行代码进行了修改
System.out.println(“I like storm......”);
改完后也要合并到 master。此时,由于两个分支对同一行代码都做了修改,就会出现代码冲突问题!
4.冲突问题的解决
B 分支的开发者李四首先要 git pull
最新的代码,此时会出现如下冲突提示:
<<<<<<< HEAD
System.out.println(“I like spark......”);
=======
System.out.println(“I liike storm......”);
>>>>>>> 7670872121112446521ef12f5050e2ba825ce994
上面的意思,就是说 master 分支和 B 分支出现了冲突。
第一行是 HEAD 代码,因为 HEAD 目前指向 master,也就是 master 的代码;第二行是张三的代码。
此时李四和张三沟通后选择将冲突的内容删除掉,保留正常内容即可解决冲突。