|
@@ -19,6 +19,12 @@
|
|
|
- 修改的文件执行`git diff`查看修改造成的差异
|
|
- 修改的文件执行`git diff`查看修改造成的差异
|
|
|
9. 工作进度保存
|
|
9. 工作进度保存
|
|
|
|
|
|
|
|
|
|
+git存储的并非是文件差异,而是文件快照。在git中,每当你提交更新或保存项目状态时,他基本上就会对当时的全部文件创建一个快照并保存这个快照的索引(为了效率,git不再重新存储未修改的文件,只保留一个链接指向之前存储的文件)
|
|
|
|
|
+
|
|
|
|
|
+git对待数据更像是一个**快照流**
|
|
|
|
|
+
|
|
|
|
|
+git中所有的数据在存储前都计算校验和,然后以校验和来引用(SHA-1散列的校验和机制)
|
|
|
|
|
+
|
|
|
## Git初始化
|
|
## Git初始化
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
@@ -476,4 +482,317 @@ index e4311de..915ffc6 100644
|
|
|
|
|
|
|
|
使用该命令确实是快,但是丢失了Git暂存区带给用户最大的好处:对提交内容进行控制的能力
|
|
使用该命令确实是快,但是丢失了Git暂存区带给用户最大的好处:对提交内容进行控制的能力
|
|
|
|
|
|
|
|
-###
|
|
|
|
|
|
|
+## Git重置
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+root@cong:~/demo# git log --pretty=raw
|
|
|
|
|
+
|
|
|
|
|
+commit c5022c3c9befd5fafe184e06e79856dee0d91939
|
|
|
|
|
+tree 53655169badfdf496b4119020fb327afb132357f
|
|
|
|
|
+parent c63851abd060426eec65a4bf0f89bf50ca12bf07
|
|
|
|
|
+author Your Name <4534523453@qq.com> 1645668068 +0800
|
|
|
|
|
+committer Your Name <4534523453@qq.com> 1645668068 +0800
|
|
|
|
|
+
|
|
|
|
|
+ append line qwer
|
|
|
|
|
+
|
|
|
|
|
+commit c63851abd060426eec65a4bf0f89bf50ca12bf07
|
|
|
|
|
+tree e3d24dd8d55570111f5672fd888bbbabe74854d4
|
|
|
|
|
+author 1 <32452345@163.com> 1645601393 +0800
|
|
|
|
|
+committer 1 <32452345@163.com> 1645601393 +0800
|
|
|
|
|
+
|
|
|
|
|
+ welcome
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+通过`git log --pretty=raw`查看提交日志,其中 `commit`行后40位数字/字谜对应的本次提交的唯一标识,`tree`对应提交的目录树
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+vim .git/refs/heads/master
|
|
|
|
|
+
|
|
|
|
|
+> c5022c3c9befd5fafe184e06e79856dee0d91939
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+通过查看master文件的内容,对比`master`文件的内容和`git log`打印的日志发现,`master`文件记录的即使分支中最新提交的ID
|
|
|
|
|
+
|
|
|
|
|
+引用`ref/heads/master`像一个游标,在有新的提交发生时指向新的提交,git提供`git reset`可以将游标指向任意一个存在的提交ID
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+root@cong:~/demo# git reset --hard HEAD^
|
|
|
|
|
+
|
|
|
|
|
+HEAD is now at c63851a welcome
|
|
|
|
|
+
|
|
|
|
|
+root@cong:~/demo# vim .git/refs/heads/master
|
|
|
|
|
+
|
|
|
|
|
+> c63851abd060426eec65a4bf0f89bf50ca12bf07
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+`HEAD^`表示了HEAD的父提交,这条命令相当于将master充值到上一个提交上,再查看`.git/ref/heads/master`文件可以就知道文件已经更改
|
|
|
|
|
+
|
|
|
|
|
+我标识为`c5022c3c9befd5fafe184e06e79856dee0d91939`的commit,是在welcome.txt文件后添加了一行`qwer`,当使用`git reset --hard HEAD^`之后,`welcome.txt`文件添加的`qwer`被撤销
|
|
|
|
|
+
|
|
|
|
|
+**但是**,如果`reset`到了错误的版本,并且不记得reset之前commit的标识,如何**挽救错误的重置**呢
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+vim .git/logs/refs/heads/master
|
|
|
|
|
+
|
|
|
|
|
+0000000000000000000000000000000000000000 c63851abd060426eec65a4bf0f89bf50ca12bf07 1 <32452345@163.com> 1645601393 +0800 commit (initial): welcome
|
|
|
|
|
+c63851abd060426eec65a4bf0f89bf50ca12bf07 c5022c3c9befd5fafe184e06e79856dee0d91939 Your Name <4534523453@qq.com> 1645668068 +0800 commit: append line qwer
|
|
|
|
|
+c5022c3c9befd5fafe184e06e79856dee0d91939 c63851abd060426eec65a4bf0f89bf50ca12bf07 Your Name <4534523453@qq.com> 1646018312 +0800 reset: moving to HEAD^
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+通过`.git/logs`目录下日志文件记录了分支的变更
|
|
|
|
|
+
|
|
|
|
|
+git提供了`git reflog`命令,对这个文件进行操作,使用`show`子命令可以显示此文件的内容(不用通过vim查看)
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+root@cong:~/demo# git reflog show master
|
|
|
|
|
+c63851a (HEAD -> master) master@{0}: reset: moving to HEAD^
|
|
|
|
|
+c5022c3 master@{1}: commit: append line qwer
|
|
|
|
|
+c63851a (HEAD -> master) master@{2}: commit (initial): welcome
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+重置master为reset之前的值,可以`git reset --hard master@{1}`命令,让welcome.txt文件又添加了`qwer`
|
|
|
|
|
+
|
|
|
|
|
+> `master@{1}`是`git reflog`命令提供的方便易记的表达式`<refname>@{<n>}`,这个表达式的含义是引用\<refname\>第\<n\>次改变时的SHA1哈希值
|
|
|
|
|
+
|
|
|
|
|
+再次使用`git reflog show master`可以发现,本次reset的记录也被记录下来了
|
|
|
|
|
+
|
|
|
|
|
+### 深入了解reset命令
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+1. git reset [-q][<commit>][--]<paths> ...
|
|
|
|
|
+2. git reset [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> \<commit\>为可选项,可以使用引用或者提交ID,如果省略\<commit\>则相当于使用了HEAD的指向作为提交ID
|
|
|
|
|
+
|
|
|
|
|
+第一种用法包含路径\<paths\>,为了避免路径和引用(提交ID)同名而发生冲突,可以在\<paths\>前用两个连续的减号作为分割,该方法不会重置引用,更不会改变工作区,而是用指定提交状态(\<commit\>)下的文件(\<paths\>)替换掉暂存区中的文件
|
|
|
|
|
+
|
|
|
|
|
+第二种方法会重置引用,根据不同的选项可以对暂存区或工作区进行重置
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+- 上图中1,2,3操作
|
|
|
|
|
+ 1. 替换引用的指向。引用指向新的提交ID
|
|
|
|
|
+ 2. 替换暂存区。替换后,暂存区的内容和引用指向的目录树一致
|
|
|
|
|
+ 3. 替换工作区。替换后,工作区的内容变得和暂存区一致,也和HEAD所指向的目录树内容相同
|
|
|
|
|
+
|
|
|
|
|
+| 参数 | 命令 |
|
|
|
|
|
+| --------------------- | -------------------------- |
|
|
|
|
|
+| --hard | 会执行上图中的1,2,3 操作 |
|
|
|
|
|
+| --soft | 会执行上图中的1 操作 |
|
|
|
|
|
+| --mixed 或 不使用参数 | 执行1,2 操作 |
|
|
|
|
|
+
|
|
|
|
|
+## 悔棋
|
|
|
|
|
+
|
|
|
|
|
+> 初始化demo环境,新建welcome.txt,提交备注为"init welcome.txt";新建demo.txt,提交备注为"init demo.txt";修改welcom.txt,修改demo.txt,只提交welcome.txt,提交备注为"qwre";
|
|
|
|
|
+
|
|
|
|
|
+日常使用git中,经常出现`git commit`之后,发现提交说明中出现了错别字,或者有文件忘记提交或者有些文件不该提交
|
|
|
|
|
+
|
|
|
|
|
+git提供`git commit --amend`修补式提交
|
|
|
|
|
+
|
|
|
|
|
+这个命令会将暂存区中的文件提交。如果自上次提交以来未作任何修改,那么快照会保持不变,而修改的只是提交信息
|
|
|
|
|
+
|
|
|
|
|
+1. 修改提交备注
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+git commit --amend -m "update welcome.txt"
|
|
|
|
|
+git log
|
|
|
|
|
+
|
|
|
|
|
+commit e3d6938f52bba3c7e6e30ddbb392e2000360e49a (HEAD -> master)
|
|
|
|
|
+Author: Your Name <4534523453@qq.com>
|
|
|
|
|
+Date: Mon Feb 28 15:25:30 2022 +0800
|
|
|
|
|
+
|
|
|
|
|
+ update welcome.txt
|
|
|
|
|
+
|
|
|
|
|
+commit 8e455596bde132a1149c426d268ea9068a2475c0
|
|
|
|
|
+Author: Your Name <4534523453@qq.com>
|
|
|
|
|
+Date: Mon Feb 28 15:00:33 2022 +0800
|
|
|
|
|
+
|
|
|
|
|
+ init demo.txt
|
|
|
|
|
+
|
|
|
|
|
+commit 8a93bdc5c142cc27881209f3948bec3c5a185402
|
|
|
|
|
+Author: Your Name <4534523453@qq.com>
|
|
|
|
|
+Date: Mon Feb 28 14:59:43 2022 +0800
|
|
|
|
|
+
|
|
|
|
|
+ init welcome.txt
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> 可以发现最新的提交记录从`qwer`变成`update welcome.txt`
|
|
|
|
|
+
|
|
|
|
|
+2. 添加未提交的文件
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+git add demo.txt
|
|
|
|
|
+git commit --amend
|
|
|
|
|
+
|
|
|
|
|
+root@cong:~/demo# git log -p -2
|
|
|
|
|
+commit 95f7ec43c54964b4afaea2bc2a7f563f81b56ad1 (HEAD -> master)
|
|
|
|
|
+Author: Your Name <4534523453@qq.com>
|
|
|
|
|
+Date: Mon Feb 28 15:25:30 2022 +0800
|
|
|
|
|
+
|
|
|
|
|
+ update welcome.txt
|
|
|
|
|
+
|
|
|
|
|
+diff --git a/demo.txt b/demo.txt
|
|
|
|
|
+index 1549b67..b258ebe 100644
|
|
|
|
|
+--- a/demo.txt
|
|
|
|
|
++++ b/demo.txt
|
|
|
|
|
+@@ -1 +1,2 @@
|
|
|
|
|
+ demo
|
|
|
|
|
++qwer
|
|
|
|
|
+diff --git a/welcome.txt b/welcome.txt
|
|
|
|
|
+index 3b18e51..009d581 100644
|
|
|
|
|
+--- a/welcome.txt
|
|
|
|
|
++++ b/welcome.txt
|
|
|
|
|
+@@ -1 +1,2 @@
|
|
|
|
|
+ hello world
|
|
|
|
|
++qwer
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+3. 取消暂存的文件
|
|
|
|
|
+
|
|
|
|
|
+先修改welcome.txt和demo.txt文件(随便改点东西),然后直接`git add *`全部添加
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+git status
|
|
|
|
|
+git reset HEAD welcome.txt
|
|
|
|
|
+git status
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+4. 撤销对文件的修改
|
|
|
|
|
+
|
|
|
|
|
+如果不想保存对welcome.txt文件的修改
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+git status
|
|
|
|
|
+git checkout -- welcome.txt
|
|
|
|
|
+git status
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 分支
|
|
|
|
|
+
|
|
|
|
|
+[git-scm文档](https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%AE%80%E4%BB%8B)
|
|
|
|
|
+
|
|
|
|
|
+测试文件新建1.txt、2.txt、3.txt,经过添加、提交操作,Git会先计算每个子目录的校验和,然后在Git仓库中这些校验和保存树对象,随后Git会创建提交对象,他除了包含提交信息外还包含指向前面那个树对象的指针
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+通过上图可以知道,Git一次测试提交(1.txt、2.txt、3.txt)产生了5个对象:三个blob对象(保存文件快照)、一个树对象(记录目录结构和文件索引)、一个提交对象(提交信息和指向树对象的指针)
|
|
|
|
|
+
|
|
|
|
|
+提交对象除了保存提交信息和树指针之外,还有一个指向上一次提交的指针,用这种类似链表的方式
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+Git 的分支,其实本质上仅仅是指向提交对象的可变指针。 Git 的默认分支名字是 master。 在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master 分支。 master 分支会在每次提交时自动向前移动
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+| 命令 | 作用 |
|
|
|
|
|
+| ----------------------------------------- | ------------------------------------------------------------------ |
|
|
|
|
|
+| git branch | 显示本地分支列表,当前分支会输出特别的颜色 |
|
|
|
|
|
+| git branch \<branchname\> | 创建分支,居于当前头指针(HEAD)指向的提交创建分支 |
|
|
|
|
|
+| git branch \<branchname\> \<start-point\> | 创建分支,基于\<start-point\>创建新分支 |
|
|
|
|
|
+| git branch -d \<branchname\> | 删除分支,会检查要删除的分支是否已经合并到其他分支中,否则拒绝删除 |
|
|
|
|
|
+| git branch -D \<branchname\> | 删除分支,强制删除,即使该分支没有被合并任何一个分支中 |
|
|
|
|
|
+| git branch -m \<oldbranch\> \<newbranch\> | 重命名分支,如果newbranch名已经存在,拒绝重命名 |
|
|
|
|
|
+| git branch -M \<oldbranch\> \<newbranch\> | 重命名分支,不管是否存在都会强制执行 |
|
|
|
|
|
+
|
|
|
|
|
+`git branch testing`命令会新建一个指针testing,指向当前的提交对象(当前分支也指向该对象),此时HEAD所标识的就是当前分支指向的提交对象(因为branch只是创建分支,HEAD还是指向当前的master分支)
|
|
|
|
|
+
|
|
|
|
|
+当`git checkout testing`切换分支时,HEAD就会指向切换到的分支上
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+当在testing和master两个分支上分别提交数据的时候,就会形成两条不同的链表,但是它们有相同的头
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+> 在切换分支时,会改变当前工作目录中的文件
|
|
|
|
|
+
|
|
|
|
|
+使用`git checkout -b <newbranchname>`可以直接创建\<newcheckname\>分支并且切换到该分支上
|
|
|
|
|
+
|
|
|
|
|
+### 分支的新建和合并
|
|
|
|
|
+
|
|
|
|
|
+当前正在开发1.1版本的项目,被告知1.0版本中存在bug。需要切换到1.0版本,并在1.0版本的分支上新建一个专门修复该bug的分支,并在通过bug测试之后将修复bug分支合并到1.0分支中,之后再切换到1.1版本的分支上
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+当前版本在master分支的C4提交对象中,修改bug的是iss53分支的C5提交。在bug修改完毕之后切换到master分支,继续开发,此时需要将c5修改完毕的bug版本合并到C4的版本中。
|
|
|
|
|
+
|
|
|
|
|
+也就是说需要将`iss53`分支合并到`master`分支中,使用`git checkout master`切换到master分支,随后`git merge iss53`将iss53合并到master分支中
|
|
|
|
|
+
|
|
|
|
|
+git会对C4、C5、C2三个版本进行简单的三方合并,得到C6版本
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+如果C6和C5修改了同一个文件的同一个部分做了不同的修改,那么就会出现**冲突**,该冲突文件会对冲突部分做出标识
|
|
|
|
|
+
|
|
|
|
|
+在解决冲突部分之后,使用`git add`命令将其标注为冲突已解决
|
|
|
|
|
+
|
|
|
|
|
+### 分支管理
|
|
|
|
|
+
|
|
|
|
|
+- `git branch`查看所有分支
|
|
|
|
|
+- `git branch -v`查看每个分支最后一次提交
|
|
|
|
|
+- `git branch --merged`查看哪些分支已经合并到当前分支
|
|
|
|
|
+- `git branch --no-merged`查看未合并工作的分支
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+很多使用开发者喜欢只在master分支保留完全稳定的代码,同时定义develop或者next的平行分支,用来做后续开发或者测试稳定性(一旦达到稳定状态就可以被合入master分支)
|
|
|
|
|
+
|
|
|
|
|
+### 远程分支
|
|
|
|
|
+
|
|
|
|
|
+远程引用是对远程仓库的引用(指针),包括分支、标签等
|
|
|
|
|
+
|
|
|
|
|
+可以通过`git ls-remote <remote>`来显式的获得远程引用的完整列表,也可以通过`git remote show <remote>`获得远程分支的更多信息;更常见的做法是利用远程跟踪分支
|
|
|
|
|
+
|
|
|
|
|
+远程跟踪分支是远程分支状态的引用,它们是你无法移动的本地引用,一旦进行了网络通信,git就会为你移动他们以精确反应远程仓库的状态
|
|
|
|
|
+
|
|
|
|
|
+比如远端仓库`git.ourcompany.com`的git服务器,从这里克隆的时候,git的`clone`命令会将你自动命名为`origin`,他去它的所有信息,创建一个指向同一个地方的本地`master`分支,这样就有了工作基础
|
|
|
|
|
+
|
|
|
|
|
+`git remote -v`查看别名和对应的远端仓库地址
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+git clone https://github.com/tencent/rapidjson.git
|
|
|
|
|
+cd rapidjson
|
|
|
|
|
+git remote -v
|
|
|
|
|
+
|
|
|
|
|
+> origin (fetch)
|
|
|
|
|
+> origin https://github.com/tencent/rapidjson.git (push)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> origin无特殊含义,与master分支名一样,只是默认值
|
|
|
|
|
+> 如果使用`git clone -o myname`,那么默认的远程分支名就会变成`myname/master`
|
|
|
|
|
+
|
|
|
|
|
+也可以手动设置远端仓库地址和别名
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+git init demo
|
|
|
|
|
+cd demo
|
|
|
|
|
+git remote add demo https://github.com/tencent/rapidjson.git
|
|
|
|
|
+git pull --rebase rapidjson master
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> 上面执行`git pull`会报错,因为当前没有分支(更没有master分支),可以新建一个文件commit一次创建出默认的master分支就行了
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+最常出现的情况就是,本地对仓库进行了一些修改(未提交),而远端仓库也被做了一些修改,本地只要保持不与`origin`服务器连接并拉取数据,那么本地的`origin/master`指针就不会移动
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+如果想与服务器同步数据,使用`git fetch <remote>`命令即可,比如这里的`git fetch origin`,git会查找origin是哪个服务器,从中抓取本地没有的数据,并更新本地数据库,移动`origin/master`指针到更新后的位置
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+#### 推送
|
|
|
|
|
+
|
|
|
|
|
+`git push <remote> <branch>`可以将仓库推送到具有写入权限的远程仓库上
|
|
|
|
|
+
|
|
|
|
|
+例如`git push origin mybranch`,实际上执行的是`git push origin mybranch:mybranch`,mybranch展开就是`refs/heads/mybranch`,意味着推送本地`mybranch`分支到远端的`mybranch`分支上
|
|
|
|
|
+
|
|
|
|
|
+相对应的`git push origin mybranch:yourbranch`,就是将本地`mybranch`分支提交到远端的`yourbranch`分支中
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+#### 跟踪分支
|
|
|
|
|
+
|