Git 学习
[toc]
luke的git手册
git对象学习
四种对象
blob
- 文件名为sha-1算法和内容hash得到的
tree
- tree对象类似目录这么一个概念,主要记录下属的blob和tree对象。
- tree本身的文件名也是sha-1的哈希值。
- Git 根据某一时刻暂存区(即 index 区域)所表示的状态创建并记录一个对应的树对象,
commit
-
commit记录的是一条commit信息,是和git commit 对应的。
-
commit链接一个tree对象。
-
commit有一个parent属性,用来将一个分支串起来。
tag
我们都知道,对一个分支来说。会一直向前走。但是有时候我们在分支上需要一个固定的坐标。就可以使用tag。
当然也可以通过移动Head指针,指向对应的Commit Id,只不过tag做了一个类似alias的功能
一个基本的流程串联
脑子里有颗树
这里是git的最底层原理,用来理解其怎么实现,但最重要的开始理解文章最开始的Git基本概念图。
git init
echo "ver1" > file.txt
git add file.txt
git status
Changes to be committed:
new file: file
暂存区新加文件file
git commit -m "first commit"
git commit 根据暂存区文件生成一个tree对象,并用commit链接tree对象。
此时的逻辑图是这样的
echo "ver2" >> file
echo "new" > new
git add file
git add new
git commit -m "second commit"
此时的逻辑图是这样的
git rm new
git commit -m "third commit"
获取和创建Git仓库
本地工作流
git add/rm
git status
git commit
git reset
git restore
git add / rm / restore
git add
git add <file> 将文件提交到暂存区
一旦文件git add后,就相当于被track了,任何对文件的改动都会被git所记录。
git restore
git restore --staged <place> 从HEAD中恢复文件到暂存区
git restore <place> 将文件从暂存区恢复到工作区
git restore --source <branch>:<place> 从其他的commit恢复文件
这里的<place> 可以是file,也可以是正则之类的东西
测验
git init
echo "123" > file
git add file
rm file
如何将file恢复。
git restore file
git commit -m "ver1"
echo "error" > file
git add file
rm file
如何恢复commit中的file
git restore --staged file git restore file
如何恢复内容是“error”的file
git restore file
git commit / reset
git commit 用来将暂存区的文件提交到本地数据库中。
git commit --ammend
会取消上一次的commit,并合并你暂存区的文件,重新提交一次commit
- 主要被用来fix上次commit忘记提交的一些细节。
- 仅仅在自己的commit后使用,因为--ammend会撤销上一次的commit。所以对公共的commit使用会影响别人。
git reset 用来回退版本
git reset HEAD
git reset --soft <verID>
git reset --mixed <verID> 默认
git reset --hard <verID>
git reset HEAD 默认使用–soft。
reset
reset --soft 本质就是移动了HEAD指针。
git reset HEAD 主要是用来回滚暂存区。
git reset HEAD
重置暂存区,主要用来roll back
git init
echo ver1 > file
git add file
git commit -m "ver1"
echo ver2 >> file
git add file
git reset HEAD
git reset 三种模式
echo ver1 > file.txt
git add file.txt
git commit -m "ver1"
echo ver2 >> file.txt
git add file.txt
git commit -m "ver2"
echo ver3 >> file.txt
git add file.txt
git commit -m "ver3"
git reset --soft
git reset --soft HEAD^
仅仅移动HEAD指针。workspace和staging area都不受影响。
git reset --mixed
git reset --mixed HEAD^
HEAD 指针移动,同时暂存区也会被回滚到ver2
git reset --hard
同时会撤销暂存区,workspace,和local repository。是一个非常危险的命令。
cherry-pick 和 git stash
cherry-pick
负责将某个commit-id的commit复制到当前分支上。
git stash
用来保存暂存区和工作区的文件内容
- git stash save "save message"。
- git stash apply stash@{num} 应用第几个存储。
- git stash list 来列举哪些存储。
交互远程仓库
远程分支和本地分支
远程分支的本质上也是一个分支。其就是在本机中远程仓库对应分支的映射分支。
远程分支的名字就是 <repo>/<local-branchname>,一般为origin/<local-branchname>。默认的远程仓库名就是origin。
git push
git push <remote> <place>
1. 将本地分支的所有commit提交到<remote>/<place>分支下,同时更新远程仓库中的对应分支。
git push <remote> <source>:<dest>
1. 同上,但是将本地分支commit提交到<remote>/<dest>分支下,同时更新远程仓库的<dest>分支。
git push <remote> :<dest> 可以删除远程分支
git fetch/pull
git fetch
会干俩件事
- 从远程仓库下载本地仓库中缺失的提交记录。
- 更新远程分支指针(如
origin/master)。
git fetch <repo> <place>
<repo> 远程仓库名
<place> 分支名
git fetch
会更新所有分支
git fetch origin foo
下载本地foo分支缺失的commit,然后更新origin/foo指针。
git pull
git pull就是在完成git fetch后,会用当前分支merge远程分支。
git merge/rebase
merge
git merge 可以分为两种情况。1. fast forward 2. 三路合并
fast forward
当前分支master和目标分支feature没有分叉。则可以直接进行fast forward合并。
三路合并
当在master分支,merge feature分支时。
- 去寻找common recent accestor,就是M3。如果期间feature分支同步过master,则会cra就会变化。
- 比较cra和当前分支diff1,cra和目标分支diff2。
- 如果俩个diff在同一位置发生改动,则冲突。否则,保留有改动的一方即可。
理解了这个原理后,如何快速造一个confict出来。
git init
echo "hello" > test.txt
git add test.txt
git commit -m "m1"
git switch -c feature
echo "world" >> test.txt
git commit -am "f1"
git switch master
echo "nihao" >> test.txt
git merge feature
rebase
Reapply commits on top of another base tip 这里的官方解释很明确
合并分支
git rebase <upstream> <branch>
1. 如果指定了branch,就会先执行git switch branch,然后执行git rebase
2. 如果没有指定<upstream> ,则默认以本分支的远程分支为upstream
流程
- 将本分支所有的commit,但是在upstream里没有的commit保存到临时区。
- 将分支指针移动到upstream,然后将临时区的所有commit依次apply。
合并commit
git rebase -i <commit-id>
- 改变commit顺序
- 合并多个commit,
- pick:保留该commit
- reword:保留该commit,但是要修改commit注释
- squash:将该commit和前一个commit合并
- drop:不要该commit
常见的使用场景
1. 准备开发feature
一般从master中checkout一个新的分支出来
git switch master
git pull master
git switch -c feature/${someone_name}/${feature_name}
2. 准备测试
一般测试时,是合到experiment分支上去的。 重新checkout一个feature的exp分支出来。
git switch experiment
git switch -c feature/${someone_name}/${feature_name}_exp
git merge feature/${someone_name}/${feature_name}
这么做的原因是因为万一experiment分支有了Bug代码,但不是你提交的。暂时修改不了,可以让自己的${feature_name}_exp作为测试分支。因为这个分支不会有别人的测试代码。
3. 准备合入master
- 合并commit成一个 git rebase -i
- git pull origin master 更新master分支
- git rebase origin/master ,当前分支rebase master分支
- git push origin 自己的分支名
4. git commit --ammend使用(新手不建议使用)
git commit -m "commit"
git push origin branch_name
这时候发现有个代码写错了,改动了一番后,想使用
git commit --ammend
这时候直接
git push -f origin branch_name
因为commit --ammend会重新生成一个commit id,和远程仓库不一致。
这里不建议新手使用是因为,如果已经把commit1提交到远程仓库,然后通过ammend再去修改,这时候需要push --force,所以只能对自己的分支这么搞,和别人合作时不可以。
犯错时用到的高级特性
- git revert 用来消除掉自己的一次commit,所以这里要求自己的commit每次最好是功能完备的。
通过找到一个commit id。
比如说 git revert -i 1e1f61f8125a1706c98a465287a5c22e15a4cc83
学习网站
git 算是日常开发中用到的非常重要的工具。建议熟练掌握。
建议完成里面所有的官卡。基本上就对git非常熟悉了。可以大胆地玩了。
learngitbranching.js.org/?locale=zh_…