git学习笔记
git和svn的区别:
1.git是分布式的,而svn是非分布式的。
2.git绝大多数操作都是本地化的,不需要网络。比方说查看提交历史。
3.git只会添加数据,不会删除数据,所以git几乎没有可能导致文件无法恢复的操作
4.存储方式:
(1) svn:按文件变更列表的方式存储消息。既即一组基本文件和每个文件随时间逐步累积的差异(它们通常称作 基于差异(delta-based) 的版本控制),也就是说 vVersion 2 中记录的不是修改过后完整的 Ffile A,而是 Ffile A 修改的部分,在 Vversion 2 中要得到完整的 Ffile A,则需要 Vversion 1.Ffile A + Vversion 2.△1才可以。
(2) git:git 会在每次提交的时候将变更的文件直接拷贝形成一个 blob 对象,而不是和上一个版本的 diff。为了效率,如果文件没有修改,git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。 git 对待数据更像是一个快照流。
工作区、暂存区、版本库:
1.各个区详解:
(1) 工作目录(Working Directory):就存放代码的地方,在这个文件夹下有一个 .git 文件,该文件存储的就是 git 的所有数据,包括 暂存区、资源库。
(2) 暂存区(Stage/Index):存放的是已暂存的内容。
(3) 本地资源库(Repository或Git Directory):存放的是已暂存的内容、已commit文件。
(4) 远程git仓库(Remote Directory):远程仓库、即已push文件。
2.关系图:
3. 文件的四种状态:
(1) 注意:
① 这里的四种状态都不涉及到远程仓库,最后一步的已提交也只是到达本地仓库。
② 已暂存、已修改、已提交这三种都是已跟踪。
③ 已修改和已暂存都位于暂存区。
(2) 四种状态详解:
① 未跟踪(Untracked):未跟踪,此文件在文件夹中, 但并没有加入到git库, 不参与版本控制. 通过git add 状态变为Staged。
② 已暂存(Staged):位于暂存区,如果该文件被修改就会变成已修改。
③ 已修改(Modified):位于暂存区后被修改但还没到资源库,也就是已经 git add 但还没有 git commit。
④ 已提交(committed):即已经安全到达本地库中。
(3) 文件四种状态和git三个区的位置图:
① 说明:
1) 工作目录下有一个 .git 文件夹,该文件夹下包含着所有 git 消息(所以该文件千万不要乱动)。
2) 未暂存的文件只会位于工作目录,而不会存在于.git下。
3) 已暂存和已提交都位于暂存区中。
图:
(4) 转换关系:
① 引起文件的状态发生变化的几点原因举例:
1) 新增文件:这个会将文件状态变成未跟踪(Untracked files)。
2) 修改文件:这个会将文件状态变成已修改(Changes not staged for commit)。
3) 删除文件:这个会将文件状态变成已修改(Changes not staged for commit)。
② 图的几点说明:
1) 该图是引起文件转变的几点原因(但不是全部,详情见第三章)。
2) 下图就是通过不同 git 命令在让文件在不同状态之间来回切换的方式。
3) 对于新增文件而言而已,状态只有已提交、已暂存、未跟踪;而对于修改、删除文件而言,其状态只有已提交、已暂存、已修改。
4) 对于新增文件,无论里面有没有内容,一旦 git add 后就会变成已暂存,而如果在变成已暂存再对其进行修改,则该文件会同时存在于已暂存和已修改。
图:
能改变文件状态的命令:
1. add:
(1) 说明:
① 将文件从已修改、未跟踪变成已暂存。
(2) git add .:添加所有文件和文件夹。
(3) git add xxx-1.txt xxx-2.txt xxx-3:添加指定文件或文件夹。
2. reset HEAD(reset XXX):
(1) 说明:
① reset 用于重置当前分支的 HEAD 指向(它不会切换分支,是在同一个分支中移动指向)。
(2) 大致流程:
① 修改前:
② 执行一次 git reset HEAD~1:HEAD~1 表示当前指向的前一次提交,所以这里就变成了C2。
③ 再执行一次 git reset HEAD~1:
④ 执行 git reset C4:reset 是重置,可以往前退,也可以往后进。
(3) 四种模式:
① 说明:
1) 上面的流程只是为了让我们能更好的入门 reset ,但实际上 reset 有四种模式,情况要比上图中要复杂的多。
2) 我们之前学习到的 git 一共有三个区域:本地资源库、暂存区、工作区。而 reset 四种模式就是影响的区域不同。
② git reset --soft:
1) 说明:
a. 这个只会影响本地资源库,但暂存区和工作目录的没有任何变化。
b.对于新增文件:file4.txt 是 C2 中新增的(C1 中没有 file4.txt)。此时执行 reset —soft HEAD~1,由于工作目录没移动指针,所以该文件仍然是存在于工作目录中的(即仍然存在于硬盘); 而由于暂存区没有改动,所以 file4.txt 仍然是在暂存区的,但是由于资源库的回退了,所以该文件就变成已暂存了。
c.对于修改文件: file4.txt 在 C2 中做了修改(C1 中也有 file4.txt )。此时执行 reset —soft HEAD~1,由于工作目录没移动指针,所以该文件仍然是存在于工作目录中的(即仍然存在于硬盘);而由于暂存区没有改动,所以暂存区的内容就和工作区的内容有偏差了,所以此时会显示有数据未提交(即处于已暂存),但和上面的差别是上面的是 new file,这里是modified。
2) 图:
a.修改前:
b.执行 git reset --soft C1:
③ git reset [--mixed]:
1) 说明:
a. 这个只会影响本地资源库和暂存区,但工作目录的没有任何变化。
b.对于新增文件:file4.txt 是 C2 中新增的(C1 中没有 file4.txt)。此时执行 reset —soft HEAD~1,由于工作目录没移动指针,所以该文件仍然是存在于工作目录中的(即仍然存在于硬盘);但暂存区和本地资源都发生了改变,所以暂存区和本地资源库是一致的,都不存在该文件,而工作区仍然存在该文件,所以处于未跟踪状态。
c.对于修改文件: file4.txt 在 C2 中做了修改(C1 中也有 file4.txt )。此时执行 reset —soft HEAD~1,由于工作目录没移动指针,所以该文件仍然是存在于工作目录中的(即仍然存在于硬盘);但暂存区和本地资源都发生了改变,所以暂存区和本地资源库是一致的,该文件在 C1 时是处于已提交状态,但执行 reset 由于不会修改工作目录,所以相当于是对已提交文件做了修改,所以是已修改状态。
2) 图:
a.修改前:
b.执行 git reset --soft C1:
④ git reset --hard:
1) 说明:
a. 该模式会影响本地资源库、暂存区和工作区。
b. 由于该模式会冲掉工作区代码,所以如果工作区有未提交的代码,则会导致代码找不到从而导致严重的问题。
2) 图:
a.修改前:
b.执行 git reset —hard C1:
⑤ git reset --merge:
1) 将目标 commit-id 和当前在工作区的文本做比较,如果存在差异则需要保留两者。
2) 在 --hard 模型中,由于它会直接重置暂存区和工作区,所以如果你当前还没有提交的内容时则会被全部冲掉,这个非常危险,而 --merge 能让你保留当前未提交的和目标提交之间的区别,这个比 --hard 安全的多。
(4) 操作某个文件或全部:
① git reset HEAD~1:影响的是全部文件和目录。
② git reset HEAD~1 file.txt:影响的只有该文件或目录(需要特别注意的是对于 --hard 模式只能操作全部,无法操作部分)。
(5) reset 后再提交:
① 说明:相当于开了一个分支。
② 流程:
1) 修改前:
2) reset 后:
3) 修改文件后提交:
(6) 注意:
① 如果我们用 reset 移动过后,需要看全部提交,可以使用 git log --pretty=oneline --all。
② 当我们使用 reset 后,资源库里的提交是一个没少,只不过是我们 HEAD 指向发生了变化而已。
③ 使用 git reset --hard 需要非常小心,如果你在没有提交的情况下使用该命令,将无法再找回这些没有提交的内容。
④ 缺省模式能操作全部和部分(某文件或某目录),但 --soft、—hard、--merge 只能操作全部,无法操作部分。
3. commit:
(1) 说明:
① 提交代码,将暂存区的内容提交到本地资源库,但是这里的本地资源库是指本地,和远程资源库无关。
(2) 命令:
① git commit -m ‘xxx’:将已暂存的内容提交到本地资源库。
② git commit -a -m ‘xxx’:将已修改和已暂存的内容直接提交到已提交,但需要注意的是,该命令无法让未跟踪的文件直接变成已提交。
③ git commit --amend:
1) 说明:
a. 该命令可以修改上一次提交消息或将本次提交追加到上一次提交中。
b. 当执行 git commit --amend 后会出现一个 vi 窗口,你需要进行 vi 编写。
④ 案例:
1) 说明:
a. 实际上是相当于把之前的哪次提交冲掉。
⑤ 流程:
1) 追加前:
2) 追加后:
⑥ 流程示意图:
1) 追加前:
2) 追加后:
4. checkout:
(1) 说明:
① 检出,它和 reset 一样,其本质都是移动 HEAD。
(2) 应用场景:
① git checkout:用于切换分支,即将 HEAD 指向另外一个分支,并重置本地资源库、暂存区和工作区。
② git checkout :
1) 使得指定文件移动指向。
2) checkout 不会影响本地资源库的指向,它改的是 暂存区和工作目录,并且会完成冲掉工作目录的代码,这个和 git reset --hard 非常像,但 hard 同时还会重置本地资源库的指向。
5. rm:
(1) 说明:
① git 中,文件可能存在于本地资源库或暂存区或工作区。
② 从暂存区和工作区中将文件删除,但不会影响本地资源库。
(2) 命令:
① git rm:
1) 这个命令,只对已提交的文件起作用,其他状态文件无法生效。
2) 如果某个文件同时存在于本地资源库、暂存区和工作区。执行 rm 会将其从暂存区和工作区同时删除(如果你手欠,手动从工作区删除再执行 rm 效果也一样),但不会从本地资源库中删除,而且该文件状态会变成已暂存,此时执行 git commit -m ‘x’ 进行提交,则会让本地资源库的文件也被删除。
② git rm -f:
1) 强制删除,对已提交、已暂存、已修改的起作用,对未跟踪无效。
2) 删除后,如果该文件之前存在于本地资源库则还需要执行 commit。
③ git rm --cache:
1) 只是从暂存区中移除。
2) 该命令对已提交、已暂存、已修改的起作用,对未跟踪无效。
3) 如果某个文件同时存在于本地资源库、暂存区和工作区,本地资源库来说是处于已暂存;对于工作区来说实未跟踪。
④ git rm –r *:递归删除,即如果后面跟的是一个目录做为参数,则会递归删除整个目录中的所有子目录和文件。
6. git fetch:
(1) git fetch <远程主机名> <分支名>:
① 如git fetch origin、git fetch origin master-1。
② 将远程仓库的更新全部更新到本地资源库,如图
用于解决冲突的命令
1. 产生代码冲突的原因:
(1) 简单来说就是本地修改的文件和目标远程库的同一个文件都有修改。这时无论是pull丶push丶merge时都会产生冲突,但merge命令会帮我们自动把那些可以处理的冲突解决掉,当git无法解决时则需要我们手动解决。
2. diff:
(1) 说明:
① git diff用来比较文件之间的不同。
(2) 命令:
① git diff <分支名1> <分支名2> :比较两个分支上最后 commit 的内容的差别。
② git diff:比较两次提交之间的差异。
③ git diff:当工作区有改动,临时区为空,diff的对比是“工作区与最后一次commit提交的仓库的共同文件”;当工作区有改动,临时区不为空,diff对比的是“工作区与暂存区的共同文件”。
④ git diff --cached 或 git diff --staged:显示暂存区(已add但未commit文件)和最后一次commit(HEAD)之间的所有不相同文件的增删改(git diff --cached和git diff –staged相同作用)。
⑤ git diff HEAD:显示工作目录(已track但未add文件)和暂存区(已add但未commit文件)与最后一次commit之间的的所有不相同文件的增删改。
3. rebase:
(1) 说明:变基,git rebase 用于把一个分支的修改合并到当前分支。
(2) 流程:
① 没有产生冲突的情况下:
修改前:
3) 在 master 分支执行 git rebase fox:
a. 将当前分支和目标分支之间的分叉产生副本,并添加到目标分支后面,并移动 HEAD。
b. 但此时你执行 git push 是会报错的,报错的原因是你当前本地分支版本低于远程分支,这个有好几种解决方法,我这里使用 git pull。
② 在 master 分支执行 git pull:
③ 存在冲突的情况下:
1) 修改前:
2) 在 master 分支执行 git rebase fox:这个由于产生了冲突,所以 HEAD 指向和 master 指向就不一样了,而且本地产生冲突。
3) 解决冲突、并 git add . 然后执行 git rebase --continue:
4. merge:
(1) 说明:将指定提交合并到当前分支
(2) 作用:
① 用于git-pull中,来整合另一代码仓库中的变化(即:git pull = git fetch + git merge)。
② 用于从一个分支到另一个分支的合并。
(3) 命令:
① git merge-m:
1) 合并分支的时候可能存在冲突,也可能不存在冲突。如果不存在冲突则它会自动提交,其提交消息为 msg;如果存在冲突则需要本地解决后手动 commit。
(4) 会不会产生新的提交的两种情况:
① 不会产生新的提交:
1) 说明:
a. 这种实际上不会产生冲突,因为提交就一条线。
2) 流程:
合并前:
b.在 fox 分支执行 git merge matser,即在 fox 分支合并 master 分支:
a)说明:因为 fox 分支比master 更新,所以这时候 git b)会提示你已经是最新版本了。
c)图:
c. 在 master 分支执行 git merge fox,即在 master 分支合并 fox 分支:
a) 说明:由于提交是一条线,所以这时只需要 master 移动指向即可,不需要产生新的提交。
b) 图:
② 会产生新的提交:
1) 流程:
a. 合并前:
b. 在 fox 分支执行 git merge matser,即在 fox 分支合并 master 分支:
5. merge 和 rebase的区别:
(1) 流程:
(2) 修改前:
① 在 master 使用 rebase 合并 fox:
② 在 master 使用 merge 合并 fox:
用于操作远程仓库的命令:
1. 关联远程仓库:
(1) 添加远程仓库地址:
① git remote add origin https://gitee.com/XXXX/git.git:
1) 如果该文件夹是没有管理远程仓库的,则可以使用这个来添加远程仓库。
(2) 更换远程仓库地址:
① git remote set-url origin https://gitee.com/XXXX/netty.git:
1) 这个是更换,区别于添加。
2. 在本地创建一个远程仓库:
(1) 方案一:
① git clone https://gitee.com/XXXX/git.git
(2) 方案二:
① git init
② git remote add origin https://gitee.com/XXXX/git.git:至此,本地并没有对应的远程分支,所以需要检出远程分支。
③ git checkout master
3. 从远程资源库拉取数据到本地资源库:
(1) git clone:
① git clone https://gitee.com/XXXX/git.git:
1) 从远程仓库拉取一个完整备份。
(2) git pull:
① git pull <远程主机名> <远程分支名>:<本地分支名>:
1) 从远程分支拉取代码,其本质相当于是
2) :git pull = git fetch + git merge。
② git pull --rebase:
1) git pull --rebase = git fetch + git rebase
4. 从本地资源库推送数据到远程资源库:
(1) git push:
① git push <远程主机名> <本地分支名>:<远程分支名>
② git push <远程主机名> <本地分支名>:
1) 如果本地分支名与远程分支名相同,则可以省略<远程分支名>。
③ git push --force origin master:
1) 强制推送,会导致远程资源库被覆盖,这个尽量避免使用。
用于操作本地仓库分支的命令:
1. 创建本地新分支:
(1) git branch fox
① 创建分支。
2. 创建远程分支:
(1) git push origin::
① git push origin fox:fox-t:将本地的 fox 分支推送到远程资源库,其名为 fox-t。
3. 切换本地分支:
(1) git checkout fox:
① 切换分支。
(2) git checkout -b fox:
① 创建并切换分支,相当于是 git branch 和 git checkout 和合集。
4. 切换远程分支:
(1) git checkout -b 本地分支名 origin/远程分支名
5. 删除本地资源库的分支:
(1) git branch -D:
① git branch -D fox:删除本地资源库名为 fox 的分支。
6. 删除远程资源库的分支:
(1) git push origin --delete:
① git push origin --delete fox:删除远程资源库上名为 fox 的分支。
7. 查看分支:
(1) git branch:
(2) 说明:查看本地分支。
(3) 图:
(4) git branch -r:查看远程分支。
(5) git branch -a:查看所有分支。
8. git stash:
(1) 说明:
① stash 本质上是将暂存区和本地资源库的内容进行提交(这个是提交是在本分支开辟了另外一个分支,当然这个分支是临时的,之后是要被抛弃的)。
(2) 流程图:
① 修改前:
② git stash save 's-1’:其提交消息即 s-1
③ 再次执行 git stash save ’s-2’:此时相当于是重新提交了一次,且会覆盖上次 stash ,其提交消息为 s-2。
④执行 git stash pop stash@{0} :恢复最近一次存储, stash 存储是一个栈,即后进先出。
⑤ 修改代码后提交到本地资源库:
⑥ 提交到远程分支:
(3) 命令:
① git stash save 's-1':存储暂存区的内容。
② git stash list:查看存储列表。
③ git stash clear:清空存储内容。
④ git stash drop stash@{num}:删除某一个,stash@{num} 是 save 时自动产生的编号。
⑤ git stash pop stash@{num}:恢复,num是可选项,通过git stash list可查看具体值。只能恢复一次。
⑥ git stash apply stash@{num}:恢复,num是可选项,通过git stash list可查看具体值。可回复多次。
(4) 注意:多次执行 git stash save ‘XXX’ 的时候,是按栈存储的(后进先出),即执行 git stash save ’s-1’ && git stash save ’s-2’。则 stash@{0} 对应 s-2;stash@{1} 对应 s-1。
(5) 用途:
① git stash 本质上是在本地分支中建立了一个临时的、会被抛弃的分支,所以有些我们并不想把代码提交上去的时候就可以使用这个。
② pull 的时候保护本地修改的代码。
其他的工具类的命令
1. 初始化本地仓库:
(1) git init:
① 初始化本地仓库,会产生一个 .git 文件,所有 git 的数据都会放在这里。
2. 查看日志:
(1) git log:
① 说明:
1) git log 显示的是提交记录(提交到本地仓库的)。
2) 默认情况下是按提交时间顺序从最近的开始。
3) 只要提交到本地仓库上的就会显示,不需要提交到远程仓库。但他们是有区别的,origin/master 的位置不一样。
(2) 图:
① 最后一次只提交到本地仓库,没有提交到远程仓库:
② 全部提交到远程仓库:
(3) git log -1:
① 说明:
1) 只显示最近的一条提交记录。
② 图:
(4) git log -S book:
① 说明:
1) 搜索提交历史,查询出第一次提交 book 这个内容(不是文件,是内容)是哪一次。
② 图:
(5) git log --pretty=oneline:
① 说明:
1) 简化输出
② 图:
(6) git log --all:
① 说明:
1) 默认情况下 git log 只能查询 HEAD 指向之前的,但如果我们用 git reset … 命令使得我们当前 HEAD指向发生了改变,那就无法查询全部了(当前分支),此时我们就可以加上 --all。
② 图:
3. 查看状态:
(1) git status:
① 说明:
1) 会显示当前所在本地分支。
2) 该命令显示的是暂存区的文件,其他的不会被显示;而这一个区的文件一共有 新增、修改、删除三种状态。
② 图:
(2) git status -s:
① 说明:
1) 是 git status 的简写。
② 图:
使用二分法调试
1. 说明:
(1) 假设我们一共提交了10次,但发现有问题,可是我们不知道是哪一次提交引起的,这时候我们就可以使用 git rebase 来进行调试。
(2) git rebase 是一种很有用的命令,用来查找哪一次代码提交引入了错误。
(3) 它使用的是二分法,既[1, 10],它会先定位到5,然后你可以使用 git bisect good 定位到7(既[5,10]),用 git bisect bad定位到3(既[1,5])。使用 git bisect reset 恢复到最近一次提交。
2. 流程:
(1) git log --pretty=oneline:我们查询出相应指针编号。
(2)git bisect start HEAD 16ae850e14f9e15d5a71bf2df581be4edcd6cda3:它会让你本地仓库的 HEAD 指针指向 HEAD 和 16ae850e14f9e15d5a71bf2df581be4edcd6cda3 的中间。
(3) git bisect good:向前再次二分
(4) git bisect bad:向后再次二分。
(5) git bisect reset:退出 bisect 模式,恢复到最近一次提交。