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 模式,恢复到最近一次提交。