需要注意的是图中的箭头代表文件走向关系,工作目录指的就是本地
书写规则:[]代表参数的意思
本文中reference代表一个引用关系的字符,建议这个引用字符写commit-id
git add [file | .] 提交到暂存区进行跟踪
git rm 取消文件跟踪状态 ,这个我有点没懂,我觉得可以先不理,好像用的也不多
git commit 从暂存区提交到提交去 (-m参数只是增加备注信息)
git commit -a 直接从工作区提交到提交区,(-a指的是add)
将工作区内容丢弃
某个文件已提交到暂存区,后来本地工作区有了新的改动,想要丢弃掉本地新改动内容,本地的内容回到暂存区内容, 所以如上图所示,暂存区会将内容复制一份覆盖掉本地。
和上面的效果差不多,区别是丢弃单个文件,加个.号这个是所有文件撤回
上面git checkout -- [file],git checkout .都有一点撤销本地最新改动的意思,那如果想要将暂存的内容也撤销呢?
将内容从暂存区中恢复到工作区
Plain Text复制代码
1
2
3
4
5
git reset HEAD
git reset HEAD [file](将指定文件从暂存区恢复到工作区)
例:
git reset HEAD
git reset HEAD src/a.html
直接写后面不跟文件名,就是将所有文件从暂存区恢复到工作区,比如我刚刚执行了git add . ,可是我有后悔了,就可以执行git reset HEAD。如果想要撤回单个文件而已,那就后面跟上具体文件路径就好了。我常常在提交到暂存区后想要执行git diff,这时这个命令就非常好用了
将文件从上次提交区内容复制一份并覆盖掉暂存区,达到的效果就是撤销了暂存区的内容,这里有点绕,我要写长一点,请看图:
我将a.html文件提交到暂存区后,执行了reset HEAD .html这句命令,我是希望将a.html文件从暂存区内撤销掉,那这时git就会将上一次提交区内的a.htm的内容复制一份覆盖掉现在暂存区内的a.html的内容,这个时候git就检测到本地工作区内容与暂存区内容不一致了,(因为暂存区内容已经等于上次提交区的内容)l,再git status 就会发现,a.html又飘红了,因为工作区与暂存区内容不一致了,提示说可以将a.hmtl提交到暂存区。
用提交区的内容覆盖掉工作区和暂存去
Plain Text复制代码
1
2
3
git checkout HEAD file
例:
git checkout HEAD src/a.html
将文件从上次提交区内容复制一份,然后覆盖暂存区并且覆盖工作区,这个达到的效果就是将本地内容回退到某一个commit版本。感觉真是太适合我这个喜欢简单粗暴的人了。
比较差异
Plain Text复制代码
1
2
3
4
5
git diff 不写参数可直接比较,比较工作区文件与暂存区文件的差异,
git diff [某次commit-id] 比较工作区文件与某次提交的差异,有2个commit-id的话就是那个commit之间的比较
git diff -cached [某次commit-id] 比较暂存区与某次提交的差异,默认为HEAD,可不填
切换分支的应用
Plain Text复制代码
1
git checkout
git checkout 就是通过移动head指针的位置,通常我们用来切换分支(思考一下背后其实也是将这个分支的内容复制覆盖掉工作区和暂存区,不过再覆盖前会试着合并本地的最新内容,如果合并失败也就切换失败)
说明:下面写的branchName:分支名字的意思 reference:是指一个能代表引用关系的,比如commit-id,
Plain Text复制代码
1
2
3
4
5
6
git checkout 指定分支名并切换过去,(head指针会移动)
git checkout -b origin/ 切换并创建一个分支,新分支内容来自远端某个分支
git checkout - 回到上一个分支(head指针会移动)
git checkout -b 创建分支并切换分支(head指针会移动)
Plain Text复制代码
1
git checkout
这里reference相当于是给一个独有的,有提交引用关系字符吧(比如commit-id),通过这个独有的字符标识找到对应的分支并切换过去,这里要注意head指针不会跟随移动,其实head的概念很重要,head是通过先指向一个特定分支,然后再指向这个特定分支的一个特定提交(一般是最近的一次),只有head指针指向的那个分支,在那个分支的做修改提交才会被git记录,如果,你当前所在的分支head指针没有指向这个分支,那么你修改提交的东西是不会被记录的。这种状态就是叫游离状态,英文叫detached head,我以前老遇到,吃了不少亏,哎。所以在游离状态下时应该只做读取的操作,改代码就算了吧
head
先杂记一下,现在还不是很懂
HEAD一般就是指向最近的一次提交commit,
回退版本
注意:下面的commit-id参数差不多代表一个引用关系,只要是独有的引用关系都可以写,不一定是commit-id
主要推荐(温柔:将本地的代码直接回退到某个版本)
revert 可以撤销指定的提交内容,撤销后会生成一个新的commit
假设有:a、b、c三个版本,使用 git revert
此时:git log记录就会是:a、b、c、d。会基于b新生成一个d出来。此时如果你后悔想恢复c的代码。非常推荐使用。
但是这里注意区分两种commit:
当讨论 revert 时,需要分两种情况,因为 commit 分为两种:一种是常规的 commit,也就是使用 git commit 提交的 commit;另一种是 merge commit,在使用 git merge 合并两个分支之后,你将会得到一个新的 merge commit
merge commit 和普通 commit 的不同之处在于 merge commit 包含两个 parent commit,代表该 merge commit 是从哪两个 commit 合并过来的。
revert 常规commit:
revert 合并后的 merge commit:
其次推荐(暴力:将本地的代码直接回退到某个版本。不可逆。更推荐上面的revert)
git reset 默认head指针就会跟着走,不存在游离状态
假设有:a、b、c三个版本,使用 git reset --hard
此时:git log记录就只会显示 a、b。此时c是丢失了的。所以很暴力。但是用revert执行一样的则会是:a、b、c、d。会基于b新生成一个d出来。此时如果你后悔想恢复c的代码,也还来的及
所以请优先选择revert。虽然我觉得reset也很好用,哈哈哈
将目标版本的内容也就是提交区的内容复制并覆盖一份到暂存区和工作区,我觉得这个比较好,但是千万注意,除非用revert不行的情况下再使用这个,但是这个的缺点就是操作不可逆,无法回退了
提交区的内容会覆盖暂存的内容,但不会覆盖工作区的内容
(--mixed是reset 默认的,所以可以忽略不写)
将目标版本的内容也就是提交区的内容复制并覆盖一份到暂存区,注意:不会复制到工作区,所以此时,工作区的内容如果与目标版本提交区的内容不一样的话,git st就会发现,暂存区的内容与工作区也不一样,会提示你可以使用git add 命令,因为暂存区的内容和目标版本的提交区是一致的。而提交区的内容和工作区不一致,
所以结论就是:
提交区的内容会覆盖暂存的内容,但不会覆盖工作区的内容
修改版本库
这个有点神奇,我测试却发现,工作区和暂存区都是我修改后的样子,暂存区和工作区没有一个是回到了目标版本的,后来发现原来是我理解错误了,真相是这样的:
修改版本库是意思我是不知道,我估摸着就是说将当前分支的head指针指向目标版本的head也就是最新提交的commit吧,
reset VS checkout
我自己是要有点懵:下面这段话摘自网络:
首先不同于 reset --hard,checkout 对工作目录是安全的,它会通过检查来确保不会将已更改的文件弄丢。 其实它还更聪明一些。它会在工作目录中先试着简单合并一下,这样所有_还未修改过的_文件都会被更新。 而 reset --hard 则会不做检查就全面地替换所有东西。
第二个重要的区别是如何更新 HEAD。 reset 会移动 HEAD 分支的指向,而 checkout 只会移动 HEAD 自身来指向另一个分支。
自己的解释:
对于第二个: reset 会移动 HEAD 分支的指向,而 checkout 只会移动 HEAD 自身来指向另一个分支。这句话真是绕的很,感觉简单的说reset就是head站着不动,只是指向的目标变了,而checkout就是head自己移动到目标的位置,
你现在在dev分支,你运行 git reset master,那么dev分支的指向就变了,变成了和master一样的那个提交(一般是回到更早之前的);在dev分支,你运行 git checkout master,那HEAD指向master分支,但是dev这个分支,它自己的指向是不变的;你在master分之,git checkout dev,可以再回到最新的开发分支,HEAD是通过先指向一个特定分支,然后再指向这个特定分支的一个特定提交(一般是时间线最靠后的),指向变了有什么用处?
a b c d master分支
a b c d e dev分支
现在HEAD指向dev,dev是指向e这个提交的; 那也就是HEAD指向的是 e这个提交,你本地的代码就是e这个提交的版本,你在dev,然后运行, git reset master, 那么 dev就会变成 a b c d, HEAD还是指向dev分支,但是指向了 d 这个提交; 你在dev,然后运行, git checkout master, 那么 dev还是a b c d e,但是HEAD指向了master,指向了 d 这个提交,你会发现,结果是一样的; 但是,git reset master的时候,dev分支本身变了, 从 a b c d e 变成了 a b c d
暂存区---隐藏的存储区
有时我们本地正在编辑内容,突然要切换到别的分支去修复bug,这是如果直接切换过去,内容冲突了的话,是无法切换成功的,git会希望你能将正在编辑的内容提交后再切换,可是写了一半的内容不想提交,就可以使用:
git stash save '备注说明' 将工作区和暂存区的内容存到一个隐藏的空间里,需要的时候再取,并将本地的工作区 变干净,这是就可以切换分支啦
git stash list 查看所有的存储信息列表
git stash apply stash@{0},这个数字0,是存储列表的下标,这条命令将存储区某条记录回复到工作区
git stash drop stash@{0} 删除存储区某条记录
合并分支
git merge
如上图,如果当前在master上想要合并next分支,使用的命令git megre next后,由于next分支是从master上e39d0b2节点上拉的,所以合并节点有三个,就是黑箭头的那三个,合并好以以后的结果会复制到工作区和暂存区,并自动生成一次提交也就是c4fe238,这个c4fe238由于是从两个分支上合并来的,所以head也就指向两个commit,也就是e5e6d02、b370926.当然一般合并可能都会冲突,只需git status查看冲突的地方,解决后再次git add/git commit就ok了
小知识点,冲突的时候,git status 查看,有些文件前面是这样标识的:
both modfied: a.html, // 这个的意思是说合并的两个分支都改动了这个文件
然后去文件里面看:
冲突的地方上面的部分代表当前分支,下面的部分代码冲突分支
git rebase
我自己没有用过,我理解也是用来合并代码的。但是使用的场景、以及合并原理和merge会有所区分
读完下面的话,我还有一个疑惑,就是rebase将当前a分支的提交放到需要被rebase那个分支b后面,那如果当前分支a的代码版本比分支b的版本更早,那放到后面不是会有问题吗
下面摘自
摘自:www.jianshu.com/p/4079284dd…
rebase会把你当前分支的 commit 放到公共分支的最后面,所以叫变基。就好像你从公共分支又重新拉出来这个分支一样。 举例:如果你从 master 拉了个feature分支出来,然后你提交了几个 commit,这个时候刚好有人把他开发的东西合并到 master 了,这个时候 master 就比你拉分支的时候多了几个 commit,如果这个时候你 rebase master 的话,就会把你当前的几个 commit,放到那个人 commit 的后面。
merge 会把公共分支和你当前的commit 合并在一起,形成一个新的 commit 提交
注意:
●不要在公共分支使用rebase
●本地和远端对应同一条分支,优先使用rebase,而不是merge
抛出问题:
为什么不要再公共分支使用rebase? 因为往后放的这些 commit 都是新的,这样其他从这个公共分支拉出去的人,都需要再 rebase,相当于你 rebase 东西进来,就都是新的 commit 了
●1-2-3 是现在的分支状态
●这个时候从原来的master ,checkout出来一个prod分支
●然后master提交了4.5,prod提交了6.7
●这个时候master分支状态就是1-2-3-4-5,prod状态变成1-2-3-6-7
●如果在prod上用rebase master ,prod分支状态就成了1-2-3-4-5-6-7
●如果是merge 1-2-3-6-7-8 ........ |4-5|
●会出来一个8,这个8的提交就是把4-5合进来的提交
merge和rebase实际上只是用的场景不一样 更通俗的解释一波. 比如rebase,你自己开发分支一直在做,然后某一天,你想把主线的修改合到你的分支上,做一次集成,这种情况就用rebase比较好.把你的提交都放在主线修改的头上 如果用merge,脑袋上顶着一笔merge的8,你如果想回退你分支上的某个提交就很麻烦,还有一个重要的问题,rebase的话,本来我的分支是从3拉出来的,rebase完了之后,就不知道我当时是从哪儿拉出来的我的开发分支 同样的,如果你在主分支上用rebase, rebase其他分支的修改,是不是要是别人想看主分支上有什么历史,他看到的就不是完整的历史课,这个历史已经被你篡改了
常用指令
●git rebase -I dev 可以将dev分支合并到当前分支 这里的”-i“是指交互模式。就是说你可以干预rebase这个事务的过程,包括设置commit message,暂停commit等等。
●git rebase –abort 放弃一次合并
●合并多次commit操作: 1 git rebase -i dev 2 修改最后几次commit记录中的pick 为squash 3 保存退出,弹出修改文件,修改commit记录再次保存退出(删除多余的change-id 只保留一个) 4 git add . 5 git rebase --continue
配置远程映射
需要注意的是上面那个origin只是一个别名而已,你想取什么都行,后面跟上远程仓库的地址
git remote -v 查看远程配置仓库的地址
拉取远程分支
git fetch origin/master
拉取远程分支master的内容,注意,我们本地其实是有两条线,一条是本地线,一条是远程的线,这个命令仅仅是将远程的master上的最新内容拉到我们本地代表远程的那个线上,如果想要本次拉取的内容能合并到本地工作区内,还需要git merge一下
看起来git fetch 太麻烦,得操作两遍,那么可以使用git pull
git pull = git fetch + git merge
从远程拉取最新内容,并同步合并到本地工作区
修改最近一次commit的备注信息
修改最近一次commit的备注信息,网上写的是git commit --amend '备注信息',但是我试了,报错了,不过可以有另一个办法,就是直接在命令行里打git commit --amend,这时会跳出vi编辑器,第一行就是前一次提交的备注信息,只要修改成你想要的就可以了
用本次提交的版本覆盖掉远端仓库
标签Tag
创建标签
查看标签
将本地标签推送到git服务器
删除标签
每次有新tag推送到git服务器注意事项
1到package.json中将version的版本号更改掉,建议与tag号一致。重点是改掉。因为npm包在下载时会识别这个版本号变了才会更新。
2然后一定要记得build操作
3整体步骤:修改组件逻辑代码---> 修改package.json的version-->build--->add-->commit-->add tag---->push---> 到项目代码中找到package.json的dst依赖包,将版本号更改为最新的tag号,然后npm最新的包
快要写哭了