在版本的迭代开发过程中,相信很多人都会犯错误(至少梁旭有过几次这样的经历)。在这种情况下,菜鸟程序员可能会感到震惊和不知所措。资深程序员会微微一笑,摸摸发亮的额头,然后默默回滚版本。对于版本回滚,我们经常会用到两个命令:gitresetgitrevert这两个命令有什么区别呢?别着急,后面我们会详细介绍。gitreset假设我们的系统现在有如下提交:其中:A、B为正常提交,C、D为错误提交。现在,我们要回滚C和D,此时HEAD指针指向D提交(5lk4er)。我们只需将HEAD指针移动到提交B(a0fvf8)即可。有git基础的人肯定会想到gitreset这个命令。完整的命令如下:gitreset--harda0fvf8命令运行后,HEAD指针会移动到SubmitB,如下图:此时远程仓库的HEAD指针保持不变,为还是在SubmitD上。因此,如果直接使用gitpush命令,是无法将修改推送到远程仓库的。此时只能使用-f选项强制提交到远程仓库:gitpush-f这种方式回滚代码的缺点很明显,就是会让HEAD指针后移,从而丢失后续的提交信息。如果以后突然发现,C和D是多么美妙的点子,却早已消失在历史的长河中。而且有些公司(比如良旭的公司)明令禁止使用gitreset命令回滚代码,原因同上。所以,我们需要找到一个既能回滚代码又能保存错误提交的命令。这时候gitrevert命令就派上用场了。gitrevertgitrevert的作用是通过反向创建一个新版本。这个版本的内容和我们要回滚到的目标版本是一样的,只是HEAD指针指向的是这个新生成的版本,而不是目标版本。如果使用gitrevert命令来实现上面的例子,我们可以这样做:先revertD,再revertC(如果有多个提交需要回滚,需要从新回旧):gitrevert5lk4ergitrevert76sdeb会生成两个新的提交:D'和C',如下图:只有两个提交需要revert,我们可以一个一个回滚。但是如果有几十个呢?一个一个回滚肯定是效率太低,容易出错。我们可以使用以下方法进行批量回滚:【自动提交commit】gitrevertOLDER_COMMIT^..NEWER_COMMIT【自己提交commit】gitrevert-nOLDER_COMMIT^..NEWER_COMMITgitcommit-m"revertOLDER_COMMITtoNEWER_COMMIT"推荐使用【提交自己的commit】此时错误的commitC和D还保留着,也有后续dumping之用。而且,如果这样做,HEAD指针会向后移动,可以直接使用gitpush命令推送到远程仓库。而这种做法正是公司所鼓励的。让我们举一个更难的例子。假设现在有三个提交,但不幸的是,错误的提交在中间。如下图所示:此时显然不能直接使用gitreset命令将HEAD指针重置为commitA,因为commitC是正确的,需要保留。先回滚所有的提交C和B,然后使用cherry-pick命令将C提交重新生成一个新的提交C'',这样就完成了回滚提交B的需要。完整的过程如下:通过上面的比较,可以发现gitreset和gitrevert最大的区别就是gitreset会丢失后面的提交,而gitrevert是通过reverse的方法重新创建一个新的提交,同时保留原来的提交。在企业中,尽量使用gitrevert命令,尽量不要使用gitreset命令。例如,如果git提交链是A->B->C->D如果要还原B、C和D,除了一一还原,还可以使用rangerevertgitrevertB^..D这样B,C,D都被还原,变成:A->B->C->D->D'->C'->B'用法是:gitrevertOLDER_COMMIT^..NEWER_COMMIT如果我们想把这三者结合起来一个revert不会自动生成三个新的commit,而是用一个commit来完成,可以这样做:gitrevert-nOLDER_COMMIT^..NEWER_COMMITgitcommit-m"revertOLDER_COMMITtoNEWER_COMMIT"下面的例子说明thecurrentgreencommitID:27ac0fc51e99f292b7677baecc3ef7fb0ccb38d0HEADmain,?origin/main?????commitID:?298eae0c28e57ad6224d4c0bc76665d97602603d...add?d?????commitID:?27ac0fc51e99f292b7677baecc3ef7fb0ccb38d0add?c?????commitID:?6dabf4344d4aed95b1e3bb8b0d2b56046d66f37e回滚到addcgit?revert?-n?27ac0fc51e99f292b7677baecc3ef7fb0ccb38d0^..?298eae0c28e57ad6224d4c0bc76665d97602603dgit?cm?-m??"revert?to?add?c"gitdiff6dabf4344d4aed95b1e3bb8b0d2b56046d66f37e//为null说明成功回滚reset和revert的区别gitrevert是用新的commit回滚之前的commit,gitreset是直接删除指定的commit。在回滚操作方面,效果类似。但是以后继续合并旧版本的时候就不一样了。因为-gitrevert是用reversecommit来“中和”之前的commit,所以以后合并老分支的时候,这部分变化不会再出现,而gitreset是把某个分支上的一些commit删除,所以再次与旧分支合并时,这些回滚的提交还是应该引入的。gitreset是将HEAD后移,gitrevert是将HEAD前移,但是新commit的内容与要revert的内容正好相反,可以抵消要revert的内容。git通用设置gitconfig--globalalias.cocheckout#配置checkout的别名gitconfig--globalalias.cicommit#配置commit的别名gitconfig--globalalias.cmcommit#配置commit的别名gitconfig--globalalias.ststatus#配置状态别名gitconfig--globalalias.brbranch#配置分支别名gitconfig--globalalias.cpcherry-pick#配置cherry-pick别名gitconfig--globalalias.rbrebase#配置rebase的别名gitconfig--globalalias.rsreset#配置reset的别名gitconfig--globalalias.rvrevert#配置revert的别名Typescripterrorignoresinglelineignore//@ts-ignoreignorefulltext//@ts-nocheck取消忽略全文//@ts-checkgitco4e3aa9c4c269bad00b619b14e26356cbe93e967c-bdev_libin#根据cmID创建分支gittagV_testcommmitid#根据cmID创建taggitconfig--globalalias.cocheckout#配置别名ofcheckoutgitconfig--globalalias.cicommit#配置commit的别名gitconfig--globalalias.cmcommit#配置commit的别名gitconfig--globalalias.ststatus#配置状态别名gitconfig--globalalias.brbranch#配置分支别名gitconfig--globalalias.cpcherry-pick#配置cherry-pick别名gitconfig--globalalias.rbrebase#配置rebaseAliasconfig--globalalias.rsreset#配置重置别名gitconfig--globalalias.rvrevert#配置恢复别名gst='gitstatus-sb'aliasga='gitadd'aliasgc='gitcommit'aliasgco='gitcheckout'aliasgcob='gitcheckout-b'aliasgl='gitpull'aliasgp='gitpush'aliasglog="gitlog--graph--pretty=format:'%Cred%h%Creset-%C(黄色)%d%Creset%s%Cgreen(%cr)%C(粗体蓝色)<%an>%Creset'--abbrev-commit--|less"gitconfig--globalalias.cicommitgitconfig--globalalias.cocheckoutgitconfig--globalalias.ststatusgitconfig--globalalias.rbrebasegitconfig--globalalias.ll"log--oneline--decorate--color"gitconfig--globalalias.lc"log--graph--color"brewinstalltigcd~-设置别名vim.bash_profile别名ll='ls-alF'aliasla='ls-A'aliasl='ls-CF'aliastt='tig--all'exportPATH=/Users/momo/code/flutter/bin:$PATHsource。bash_profileGit暂存区管理gitstash#暂存区gitstashpop#恢复暂存区gitstashlist#列出所有stashgitstashapply#恢复暂存区内容gitstashdrop#删除暂存区gitstash(gsta):放所有暂存区将文件移动到“存储区”,类似于另一种工作区gitstashlist:查看存储队列(Stashlists)gitstashapply:将最新的存储恢复到临时存储区(可以使用gitstashapplystash@{num}(numstartscountingfrom0)commandtouseanystashesinthequeue)gitstashclear:清除存储队列gitstashsave"nameofthestash":命名存储设置gitstashpop(gstp):将最新的stash恢复到暂存区并从stash队列中删除这个stashgitstashdrop(gstd):从stash队列中删除最后一个stash(stash@{0})(gitstashdropstash@{num}删除从存储队列指定存储)远程分支管理gitpull#抓取远程仓库的所有分支更新并合并到本地gitpull--no-ff#抓取远程仓库的所有分支更新并合并到本地,do不快进合并gitfetchorigin#抓取远程仓库更新gitmergeorigin/master#将远程master分支合并到本地当前分支gitcheckout--trackorigin/branch#跟踪远程分支并创建相应的本地分支gitcheckout-b
