【重要】git merge(包括pull时的自动merge)的HEAD都是本地当前分支(即我们控制台上显示的当前分支),但是git rebase时则不一样,HEAD是“远端分支”【比如我们在dev分支下 rebase master,则HEAD是master而非dev】
还有就是解决冲突的时候不能一刀切,只用远端的或只用自己的,这个是有很大问题的(哪怕冲突的内容是import),因为远端冲突部分和本地冲突部分它们并不是完全冲突,里面是有一些需要提取出的共用数据的(比如本地冲突里部分import是需要不能删)
(.gitignore无法忽略那种已经有提交记录的文件,比如environment配置,我们提交的时候是prod,但是下载到本地调测时需要为dev,所以我们改为dev,但是本地调测好提交到远程仓库时不能把environment的修改也提交,因此一开始我想在.gitignore里添加对environment文件的忽略,然后git status发现还是对environment文件追踪了;但是如果我创建一个新的文件如test.txt,然后在.gitignore里添加对它的忽略则是可以成功的;
可以通过git update-index –assume-unchanged environment来实现对已经提交过的environment文件的之后的忽略;
这种方式也有缺点,就是刚开始我们的某个文件即便修改了也不需要提交于是用了这种方式,但是随着项目的进行这个文件修改了其他的内容是需要提交的,然后我们add没有进来,而且致命的是IDE也不会提示这个文件比较特殊。。
所以就可能造成提交的有效代码不完全产生bug;所以除了那种environment文件或package-lock.json文件,其他文件最好不要用update-index...的方式来忽略提交;其他的文件最好还是通过git add .,然后再执行一次git reset -- src/a.java b.java【注意--左右的空格】来忽略待提交文件)
一:常用命令
1.先进入项目目录,然后git init;则会为此 项目/目录 创建一个本地仓库(或重新初始化这个本地仓库),可以用ls -a ./看到多了.git目录;
或者git init /home/silentdoer/GitTest/proj;则git会判断该目录是否存在不存在创建proj目录然后为它创建本地仓库否则直接为该目录init或reinit;(注意,默认情况下会自动创建一个master的分支,但是如果是通过clone -b那么默认创建的就不一定是master了可能是dev)【git init aFolder的aFolder可以是已存在的目录/项目,也可以是还不存在的,已存在的只是会在其根目录下创建.git目录及相关文件,但是项目的文件还需自己手动add .而如果aFolder不存在则创建此目录和其根目录下的.git目录及相关文件)
或者直接cd到已有项目的根目录,然后git init(后面没有其他参数),那么git会在当前目录创建一个git空仓库(里面的文件需要手动git add .)
2.git clone url(如https://github.com/Silentdoer/silentdoer.git);这个命令很重要,一般第一次下载项目就用这个命令(会和远端仓库建立连接),如果不是下载默认的master分支则要用如:git clone -b dev url(-b表示branch,dev表示是dev这个分支)【如果本地已经存在项目,可以git init 后remote add origin xxx来和远端的空仓库建立关联,是github可以直接git push origin master,如果是gitee貌似要先git pull origin master --allow-unrelated-histories之后(注意本地必须先提交,然后记得将本地的.gitignore删掉不然会和服务端冲突很麻烦)修改冲突文件和git add .然后git push origin master;最新:gitee里可以对创建的项目先进行清空,然后客户端remote add后直接push 即可(已经commit);最最新:创建gitee项目时不要勾选用xxx来初始化这个项目就等同于一个清空后的项目】
还可以在下载的时候同时重命名,否则上面的默认是在当前目录下创建一个silentdoer目录,重命名的方式就是最后加个要改的名字即可,如。。。silentdoer.git testDemo,就会重命名为testDemo
下载好后就和远端仓库建立好连接了(注意:git clone所在的目录应该是项目的上级目录而不是项目根目录,如应该是IDEAProjs这个目录,然后clone时会自动创建项目目录),然后是从这个目录创建项目,注意要用import project而不要create,且选择maven;
git clone后默认就类似执行了git remote add origin httpxxx;(因此对于git clone的仓库是可以直接git push origin xxx的)
3.git add file;将file文件放到待提交文件的缓存里;这个file可以是目录(即只是add某个目录及其内部的所有文件,和git -rm --cached不同即便添加的是目录文件也不需要-r参数),前提是它不是空目录(git add本质上是为非目录文件服务,如果目录里有文件则会将目录连同文件一起按对应结构缓存),可同时添加多个文件用空格隔开;
撤销git add .但是没有commit的文件用git reset HEAD xx.java,表示撤销add进来的xx.java文件,如果要撤销所有add的文件则直接git reset HEAD即可;
或者用 git add .;注意有个.号,将所有文件和有效目录添加到待提交缓存里;(这里可以在项目根目录,即.git目录的同级处添加.gitignore文件然后配置过滤规则,当add时就不会将过滤的文件添加缓存并commit)
4.git rm -r --cached .;将缓存里的所有文件都移出缓存,包括已经commit的,最好不要用这个否则这种情况下再commit相当于从本地仓库清除记录所有的提交文件;
5.git commit -m 'commit info';提交缓存的文件(git add)(注:这里的 -m的信息除了是提交本地仓库时的信息,push时用的也是这里的信息)(注意:git bash里commit,idea里也会刷新信息,即从cache的绿色变成普通颜色)
注意,这个是指将本地文件提交到当前的分支里(这个不需要在commit时指定本地分支名,因为当前一定是使用的某个分支,就像redis的set一样一定是处于某个内存db如第0个,如果需要commit到其他分支是需要先切换分支而不是commit时指定分支名)
【重要】可以通过git commit --date="Sun, 3 May 2020 23:31:01 +0800" -am "提交备注"来修改此次提交的时间,这里的时间格式可以通过date -R命令得到;-am的a是amend修正的意思,m就是message的意思;
如果要接着上次的提交时间来提交,还可以通过git log来查看上一次的提交时间是多少,格式一般是这样Date: Sun May 3 23:32:21 2020 +0800然后复制从Sun开始的(如果是其他日子这个会变,按自己实际的来)这个时间作为--date的选项值即可;
但是注意,这个只是修改了本地的commit时间,如果push到远端仓库比如gitee,那么那边还是会根据他的时间来记录提交记录的【所以push最好等到晚上/**来push】
而github则更加是提交记录里就是按它那边的时间来写的,所以最好是先创建一个码云的私人私密项目,然后通过修改date的方式提交到本地和push到对应码云私密项目,等放假空了再push到github,这样备份和时间显示两不误
【重要】最好还是设置一个git hooks来实现判断是否允许提交,允许提交的时间段设置为4-7点(均为0点,即4点整到7点整),防止因为本地时间是UTC时间(git,Python取当前时间都是取的本地时间)
,git hooks配置可以百度搜索,可以配置全局的,也可以配置局部的【注意要给相关的脚本可执行权限chmod 755 xxxx.py】。
如果要忽略hook,可以在命令最后加个--no-verify
6.git diff xx.java;可以比较commit后的文件版本和当前项目中对应文件的不同,如果commit后没有修改文件则不显示差异信息;
注意,git diff xx.java虽然可以查看xx.java和本地仓库最后一次提交相比的不同,但是前提是xx.java没有被add到缓存里,否则无法比较;
7.git status;查看当前仓库的状态以及哪些文件添加了哪些没添加之类的,如是初始化状态没有任何commit;(注意这个命令是会去搜索本地的.git目录中的数据,故在其它目录是无效命令),如果文件是被过滤则git status是看不到的。
8.git remote add origin https://github.com/Silentdoer/silentdoer.git;命令将本地仓库和远端仓库连接起来(其中origin可以任意,用来代表此仓库的别名,即xx...xx.git的别名),连接好后可以用git remote show来查看或git remote show 别名 查看完整信息;
【一个本地仓库需要两个remote的场景:比如你将这个demo项目提交到了git,但是同时需要提交到公司的分享仓库,这个时候就需要两个remote了】
不过由于git remote add xxx是为本仓库添加一个远端连接,故别名其实都用origin都行,因为这个命令不能访问其它本地仓库的别名;(就像公司的集群主机用户名都是admin一样)
一个本地仓库可以有多个remote仓库(可以看.git/refs/remotes目录),如origin,origin2,origin3,然后我们做git fetch origin3 branchName,或者git push origin2 branchName
9.git pull origin master(用git fetch比较好一点,git pull似乎会自动合并冲突);这个是要在push之前执行,就类似SVN里和远端要有连接经历,git remote add xxx只是本地仓库和远端绑定,但是对方需要自己有先从它那下载的经历,否则拒绝;这句话的意思是从origin仓库里checkout master这个分支到本地仓库;【git pull包含有merge,注意提交至少分两种,一种是普通提交,一种是merge提交,git能够识别发现有对应的merge提交从而允许push】
pull=fetch+merge,pull的话,下拉远程分支并与本地分支合并。fetch只是下拉远程分支,怎么合并,可以自己再做选择(即fetch会先保留冲突的两个版本,然后用户可以事后再解决冲突而不是pull时就必须解决)。
如果自己的仓库建好后不是立刻和远端建立连接并pull而是做了一些操作后才连接的那么pull可能有问题,可以试试git pull origin master --allow-unrelated-histories
;
貌似第一次push可以加上-u然后就可以解决未连通的问题?(不是,加-u不能解决那个问题,加-u是表示用某个分支作为默认分支,即后面可以直接git push即可它会自动用之前用过的git push -u origin master)
【注意】git pull只会拉去当前分支对应的远端分支的代码以及一些全局性的修改(比如创建分支,删除分支),而不会拉去其它分支的代码,所以如果要更新其它分支需要先本地checkout到该分支然后git pull拉取;
10.git push origin master(master可以换成如dev-feature);将本地仓库所有文件都提交到origin仓库的master分支;如果加了-u,那么下次可以直接git push【一个本地仓库是可以对应多个远端仓库的】,然后就默认是git push origin master,不过最好不要这么做,每次都给出仓库别名和分支名;
,最好还是弄个SSH证书到自己的github,否则每次push都要输入账户名和密码;(origin不要写错了,不然提示是否有权限提交)
重要:如果git push origin dev-feature时,本地不存在dev-feature分支,那么会报:src refspec dev-feature does not match any.
因此如果一个项目有多个分支(一般是用于项目的不同版本,最后进行分支的merge),那么开发自己的那部分时本地也是用和远端一样的分支来开发,不要本地是dev,而push的远端分支确是dev-feature;
如果需要用到其他分支的代码,可以在另一个目录里git clone -b dev xxx来获取然后将那个分支的代码复制到自己的dev-feature分支即可,而不要clone的是dev,然后提交的却是dev-feature;
步骤:先远端建立dev-feature分支,然后本地clone该分支,然后另一个目录clone dev分支,然后将本地的dev的分支的代码复制到本地是dev-feature的项目里即可;
11.git fetch origin master;从远端同步数据到本地仓库但不会要求立刻merge;(据说push是fecth+merge)
12.git config --list;查看当前git的配置信息,显示当前仓库的配置信息也会显示--global的;(包括用户名/邮箱和远程仓库信息等)
git config --global user.name 'silentdoer'可以设置当前电脑上所有的git仓库用的用户名是什么(如果只是当前仓库用这个用户名提交那么去掉--global),user.email也是同样的设置方式;
13.git log;可以查看当前分支的提交历史【如果查看dev-01分支可以git log dev-01】(可以加个--oneline选项不然会同时显示用户和提交时间,加--graph则以图形化显示左侧有*表示是一个节点,加上--all显示所有分支而不只是当前分支,加-p可以显示具体都干了啥)
注意这个命令同时还会显示相关的tag消息,所以发布版本确实加个tag即可不需要再创建一个额外的分支(但是注意tag默认不会push到远端仓库,需要用git push origin --tags命令来提交所有tag);
14.git rm -r --cached Demo.Test(和git add binFile对应);可以将缓存的目录及内部所有文件都移除(不是删除物理上的目录和文件),如果Demo.Test只是文件的话则不需要-r参数;
15.git checkout branchName;可以用来切换本地分支;(创建分支用git branch dev-xxx,然后才是git checkout dev-xxx来切换到这个分支)【注意,切换分支后本地只能看到当前分支存在的文件,不仅仅是只能看到,是真的只有该分支的文件,即切换分支可能会删除本地的文件和增加新的文件或修改本地文件】
16.git branch –d 分支名,用来删除分支(貌似只能本地);
注意这个还可以用来回到某个节点,先通过git log --all来查看节点的版本head值如1db8434,然后git checkout 1db8434,然后再执行git branch bugfix表示在这个节点创建一个分支用于bug修复;
或者直接在该节点上git checkout -b bugfix表示在该节点上(仍然要先checkout到该节点,然后再创建分支并checkout到新建的分支里)创建bugfix分支同时切换到这个分支;
重要:checkout后本地的代码也会显示为该节点时的代码,所以切换分支或节点之前最好是先将本地的未提交的先提交到本地分支,不然checkout后不敢保证再切换回来那些未提交的是否还存在;
16.git push origin remoteBranch;可以将当前本地分支推送到远端的特定分支上,注意,如果推送失败可能是本地对远端的分支数据没有更新,可以试着重新remote add一下;
17.git remote(可加上-v显示详情)命令可以查看当前本地仓库有哪些远端仓库,比如git clone后在clone的仓库里用git remote会显示origin,即git clone已经添加了一个别名是origin的远端仓库;
加上-v后显示如:
$ git remote -v origin git://github.com/schacon/ticgit.git (fetch) origin git://github.com/schacon/ticgit.git (push) /*这里有两条origin是正常的,代表fetch/pull和push都是对应同一个远端仓库*/
注:git pull origin master是指将当前仓库的当前分支push到origin这个仓库的master这个分支里,如果自己在本地仓库没有主动建立新的分支或建立了当是没有更改(类似redis的没有执行select n>0)所在分区则默认用的就是master(init时就会创建默认的分区master)
注2:查了下似乎没有可以只看一级目录的命令,用git status所有文件都列出来了,感觉不好看,而且也没有查看缓存里add了哪些的命令(貌似也是所有文件)
18.git branch [-a]可以查看当前目录的git的分支信息,git branch dev-feature表示在当前节点创建dev-feature分支;用git checkout dev则可以切换本地的分支为dev【默认如果没有指定分支则是master】
git branch -a可以同时查看本地和远程的分支,远程的分支以remotes开头,注意本地分支名最好就是和远程的一一对应不要搞本地加dev1对应的远程的分支名却是dav1
*开头表示是当前分支
用:git branch -m old_branch new_branch
来实现本地分支改名【公司git分支名有规范,不合规范不允许提交创建远端分支,之前不知道导致本地已经创建了不合规范的分支,用这个命令就可以修改】
19.git merge dev,如果当前的本地分支是master,则这个表示是合并dev分支到master分支上;
(经过测试,比如最新版本应该是dev分支,然后我clone时没有指定导致默认的是master,然后我想切换为dev分支并pull,但是checkout dev分支后再pull dev分支到本地不会和之间clone -b dev一样的效果,而是很多坑爹的情况,最终还是规定就直接clone自己指定的
分支,如果不知道哪个分支是最新的,那就看每个分支的提交记录或问下别人,想了下还是问下别人靠谱,看哪个分支的提交时间不靠谱,毕竟分支本来就是为了能够并行开发出现的产物)
(不用问也行,用git log来看(后面的是提交的message)
git rebase除了合并多次提交外,它还有一个重要的功能,即在master上merge dev分支之前,先pull master分支确保本地master是最新(并发问题不考虑),然后切换为dev分支,将master rebase到dev分支(即可以理解为让dev分支的开发是基于最新的master节点创建的分支进行开发的【最开始当然是基于最新的master,但是开发dev过程中master可能已经被别人合并过了,所以需要rebase命令】)
步骤为:本地先切换为master分支,然后pull最新的master代码;接着又切换为dev分支执行git rebase master;解决完冲突之类的后add并commit到本地dev分支【如果有远端仓库最好push,如果是pr的形式合并到远端则必须push】;然后再切换为master分支merge dev分支;
如果是合作开发(基本都是),合并到master的操作是通过提交一个pr的形式,则最后一步的本地切换master分支merge dev可以改成在Git服务【如码云】里创建一个dev到master合并的pr(需要将rebase后的dev分支push到远端);然后review后合并,然后本地master仓库pull最新合并的代码;
【注意】git rebase master它的原理是将我们的dev分支的最早的一次提交(相对于我们上一次和master同步的节点之后的最早的那次,而不是整个提交历史最早的)移到最新的master的最后一次提交里
,如果产生了冲突是需要先解决冲突之后(可以用git status查看,标红的就是有冲突的,而那些自动合并了的就直接进缓存里),用git add .命令将解决了冲突的文件添加到缓存(不需要commit);
,然后用git rebase --continue来继续迁移相对的第二早的提交【在控制台上可以看到进度,我这边可以看到两次相对dev提交写了REBASE 1/2】,循环我们的相对的所有提交之后就rebase成功了【自动提交到本地,可以手动push到远端】
【注意如果git rebase过程中有冲突,这个时候去看代码是可能没有我们写的代码的,因为git rebase本质上也是merge,将我们的提交merge到masterTmp上,因此可能是最后的几次提交的“merge”才能看到我们的代码,rebase之前最好先提交到远端防止出问题好
可以从远端重新拉去一份,没问题再删除远端节点重新push即可】
(如果rebase一半不想继续了,可以用git rebase --abort退出rebase的context,那么就相当于没有执行git rebase master,之前为每次相对提交做的解决冲突的工作会被废弃【所以最好不要半途而废】);
注意,如果在rebase之前就已经push到了远端,那么我们rebase后由于本地的dev和远端dev的记录是不同的,所以push会被拒绝,因此需要先pull dev【然后这个时候又可能产生冲突。。又要解决冲突(这个就需要add和也要commit(可以接着push或不【假设分支是你一个人在开发就别push了,如果是多个人在开发就push】))】【这种情况有问题,会出现master和远端dev直接一直循环冲突(rebase和pull产生的),最好是本地rebase后删掉远端wlq_dev分支然后再git push origin wlq_dev新建一个dev分支】
【注意删除远端分支我这边是远端分支wlq_dev是我push创建,且只有我push过,这种情况下我删除成功了(我公司限制不允许强制提交【类似覆盖】),不是这种情况我不清楚】
【删除远端分支wlq_dev,自己本地当前可以处于wlq_dev也可以不是这个分支,删除远端分支不会导致本地分支被删除,命令是:git push origin --delete wlq_dev
】
【所以在可以提pr之前最好是自己的dev只commit不push那么快,基本不会出现电脑没了的情况。。】
【注意,rebase一般是需要提pr了才做这个操作,否则基本上不会做这个操作的;不过也可以多次rebase。。】
【最好是每个成员都创建自己的dev分支,如wlq_dev,而不要多个人开发同一个dev分支,因为每个人肯定都是开发一个小模块,小feature或修正一个小bug,不可能说一个小feature还两个人一起搞,如果有说明还可以再细分工作】
20. git blame filename可以查看git项目下的某个文件的创建者信息,日期,修改者,修改部分等信息;如:git blame ./src/main/resources/application.yml
21.git revert commitId,是指将commitId这次b提交取消掉(或说生成一次b提交内容的对立内容的提交),而不是回滚的意思,所以提交 a,b,c三次后如果revert b,那么b文件会没有,但是c文件还存在,而不是之前理解的回退到b提交的版本;
同时revert后会有新的commit记录比如记作commitRevertB,然后如果revert commitRevertB那么相当于取消(取消B提交),即取消该次revert,这样b文件又会出现;
注意,git revert commitId(假设在master上做的),那么要push origin master才会在远端生效;
22.给那种prod(上线的版本)加上tag标识一下(否则就不太好区分哪个节点它是线上的版本,哪个节点只是普通的提交),用git tag -a v2.1.1 -m "线上的第2.1.1个版本";
git tag -ln可以查看所有的tag的详细信息
不过一般是如果当前主分支的某个节点将会作为发布版本,那么就直接在该节点上创建一个分支并且叫做prod-v5_0_0来表示线上的5.0.0版本;(还是用git tag -a tagName -m 'message'来标识某个节点)
23.将本地创建的分支的内容推送的远端的该分支上(注意远端还没有创建该分支),可以用git push origin dev:dev表示(左边表示本地的,右边表示远端的,推送后远端自然会创建dev分支,并控制台信息里可以看到[new branch] dev -> dev;
但是经过测试其实如果本地的和远端的分支名一模一样的话,可以直接git push origin dev即可会自动在远端创建dev分支);
而如果要删除远端的某个分支,可以用git push origin :dev表示推送一个空的分支到远端的dev分支,其实就是删除远端的dev分支;
24.git checkout .和git clean -df,这两个命令的作用是取消/回滚本地修改/新增(如果以已经缓存先git reset HEAD),比如我修改了a.java文件但是想要恢复没修改前的状态则可以用git checkout .,这里git clean的作用则是删除那些新增的文件加上-df是同时删除目录的意思;
25.git status显示的中文会是8进制的名字,可以用git config --global core.quotepath false
来显示中文名;
26.修改上一次提交的时间:git commit --amend --date="Sun May 3 23:32:21 2020 +0800";然后会弹出一个TUI框,直接按Ctrl+X退出即可,然后可以用git log查看最新的提交的时间已经改了,不过这里有个问题就是如果此时要push可能会提示需要先pull,然后pull后log里会有老的提交记录(所以注意如果发现commit的时间错了,尽量不用push那么快,先改了时间后再push)
这样可以节省很多时间,比如我一个项目里主服务/微服务/通用module等都在,然后A只能拉取主服务和通用Module,B只能拉取微服务和通用Module,这样子就很容易实现;
然后就是比如Java里分为Project和Module,我们应该为每个Module建立仓库提交,而不是整个Project,然后别人clone时是先本地创建project,然后到project根目录来进行不同的module的clone工作,
之所以要这么做是比如通用Module里有很多主服务和微服务公用的model(比如实人认证的一些Model),这样双方就可以很容易的用同一个Model就行不用两个地方都创建,而且某一方改了跟对方说一句让他拉取下就行,
而不用重新打成jar包发给对方;
git如果要取消正在做的事情,比如rebase,可以用--abort来实现,git rebase --abort
git checkout - -ours xxx/A.java // 抛弃远端的版本完全采用自己的
git checkout - -theirs xxx/A.java // 抛弃自己的版本
不过上面两个命令还是会有问题,它会同时将冲突的文件拆分为不过文件一起提交;
git冲突只存在于仓库的分支之间,比如本地仓库a分支和b分支或者远端仓库a分支和本地的a分支【最好不用pull远端a分支到本地b分支上,没测试过,也许不允许这么pull】,如果还没有提交到本地,则pull是不允许的;
git merge或者pull时如果a.java文件在两个分支上的提交存在冲突,则它不会像SVN一样生成两个冲突文件(总共三个,一个是原来的,另外两个是一个是本地的,一个是远端的),而是就在a.java文件里处理冲突,通过<<<<<<<<< HEAD等标识来指示哪些地方有冲突。
冲突内容大概是这样子:
<<<<<<< HEAD master commit conflict comtent ======= hotfix-001 commit conflict content >>>>>>> hotfix-001
注意,一个冲突文件里可能有多个上面的冲突段,这里的HEAD是表示当前分支的当前节点的意思(最后一次提交的节点,current指针指向的节点),然后下面就是当前分支(master)里对冲突块内容的修改值,=======后面的则是hotfix-001分支对这冲突块内容的修改值;
这里需要手动合并这两个同一个冲突块的内容,合并好后删掉<<<<<<< HEAD ======= >>>>>>> hotfix-001这些东西,然后重新git add a.java,并且git commit到本地仓库(如果是pull产生的冲突还需要push)【注意,这里add冲突文件后的commit不能用git commit -m 'xx'的形式,只能是直接git commit,然后会弹出一个vi编辑界面,在里面编辑这次commit的备注信息,#后面的是注释不会提交上去不用管,写好commit备注信息后通过:wq就会提交到本地仓库了】
如果发现merge后的处理结果有问题,但是已经提交到了本地仓库,可以通过git reset "merge提交的上一次提交的提交码"来将当前的current指针(HEAD)指向上一次提交,那么自然就起到了回滚作用;
但是注意这种方式不会回滚本地文件的合并,即a.java文件还是处理了合并后的内容modified状态,可以用git checkout . && git clean -df来实现本地修改/新增的文件也回滚到上一次提交的内容;
如果要回滚远端仓库,比如远端仓库N的master分支要回滚到上一次提交(或者上上次),可以先在本地pull远端仓库后,在本地的master分支git reset "上一次提交码",此时如果git push是会失败的,因为本地的提交码要比远端的小,所以要用git push -f来强制提交到远端仓库,这样就可以实现回滚远端仓库了【但是注意,git是可以设置不允许强制提交的,所以这种方式未必适合一些企业比如招商银行的码云就不允许强制push】;
这种情况下可以用git revert来实现,假设我们要回退到这次提交b(当前节点是b)的上一次提交c,那么reset是git reset c,而git revert则是git revert b,然后会生成新的提交d【可以理解为d这个提交是取消b的改动,比如b是删除文件x,则d是添加文件x,b是修改文件x,b则是取消修改文件x,至于revert过程的冲突也是需要手动解决的】,然后再push就可以了;【如果是要回退到多个提交之前,则最好是先revert c(最近一次提交)【revert理解为取消某次修改的提交】,然后再revert b,然后再revert a这样子逐步回滚,会新生成三次revert提交,revert完毕后可以用rebase将它们压缩为一次提交】
git revert -n "提交码"和git reset的区别在于,git reset "提交码"是回退到提交码这个版本,后续的提交都消除掉;而git revert -n "提交码"的作用【-n是指revert后不自动提交】是取消"提交码"这次提交的修改,然后生成一个新的提交来回滚那次提交;
但是revert会出现问题,比如revert到b节点,b节点后面又提交了c节点,而c节点依赖了b节点提交的内容(比如b这次提交增加了一个工具类,而c的提交有用到这个工具类),这种情况revert b就会出现问题,或导致新提交后的d节点的代码是错的;