来源:juejin.cn/post/7071780876501123085前言使用Git作为代码版本管理,早已成为开发工程师的必备技能。但是大部分工程师还是只做最基本的saving、pulling、push。当遇到一些提交管理问题时,他们束手无策,或者用一些不优雅的方式去解决。本文分享我在开发工作中实践过的实用命令。这些都可以大大提高工作效率,解决很多棘手的场景。下面将对命令进行介绍,列出应用场景,手把手教用,让同学们读后感悟。stashdescription官方解释:当你想记录你的工作目录和索引的当前状态,但又想回到一个干净的工作目录时,使用gitstash。此命令将保存本地更改并恢复工作目录以匹配head提交。stash命令可以保存未提交的代码并使您的工作目录变得干净。应用场景我猜你心里一定在想:你为什么要干净?应用场景:某天你在特性分支开发新需求,突然产品经理过来说线上有bug,必须马上修复。这时候你的功能开发进行到一半,急着想切换到master分支,然后会看到如下错误:因为部分文件发生了变化,需要提交commit来保留工作区剪枝前清洁。因为情况紧急,不得不仓促commit,而且commit信息还随便写了一个“临时代码”,所以在这个分支的commit记录中留下了一段黑历史……(真人,见过这种commit)命令如果你学会了stash就用到了,这样你就不用那么尴尬了。你只需要:gitstash就这么简单,代码就存储起来了。当你修复线上问题并切换回特性分支时,只需要恢复代码:gitstashapplyrelatedcommands#保存当前未提交的代码gitstash#保存当前未提交的代码并添加注释gitstashsave"RemarkedContent"#列出stash的所有记录gitstashlist#删除stash的所有记录gitstashclear#应用最近的stashgitstashapply#应用最近的stash,然后删除记录gitstashpop#删除最近的stashgitstashdrop当有多个stashes时,可以指定操作stash,首先使用stashlist列出所有记录:$gitstashlistsstash@{0}:WIPon...stash@{1}:WIPon...stash@{2}:On...应用第二条记录:$gitstashapplystash@{1}pop,drop也一样。vscode集成了stashcode填写备注内容,也可以不填写直接进入。在STASHES菜单中,您可以看到已保存的藏匿处。先点击stashrecord旁边的小箭头,然后点击apply或pop恢复stashreset--软描述不触及所有文件或工作树的索引(但会像所有模式一样,将head重置为)。这使得所有更改的文件更改“更改提交”。回滚已经提交的commit,将commit修改后的内容放回暂存区。一般我们在使用reset命令的时候会多提到gitreset--hard,它可以强制commit记录回到某个节点。gitreset--soft的作用就像它的名字一样,--soft(soft)除了回溯节点之外,还会保留节点的修改内容。应用场景回溯节点,为什么要保留修改的内容?应用场景一:有时候不该提交的内容被不小心手动提交了,这时候想改回来只能重新提交,又是一个“黑历史”。应用场景二:比较规范的团队,一般要求commit的内容职责明确,粒度要细,方便后续排查问题。本来属于两个不同功能的修改,一起commit,这个不规范。这次刚好又是滑的,所以就做了一次性的commit。当你学会了reset--soft命令的使用方法后,你只需要:#恢复上次的commitgitreset--softHEAD^reset--soft相当于后悔药,给你一次改过自新的机会。对于以上场景,您可以修改并重新提交,以保持一个干净的提交记录。以上是尚未推送的commit。已经push过的commit也可以使用这个命令,但是再次push时,由于远程分支和本地分支的区别,需要强制pushgitpush-f来覆盖resetcommit。另外需要注意的是,reset--soft指定commitnumber时,会恢复从commit到最近一次commit的所有修改内容,而不仅仅针对commit。例如:commit记录有c,b,a。重置为a。gitreset--soft1a900ac29eba73ce817bf959f82ffcb0bfa38f75此时HEAD已经到了a,b和c修改的内容已经回到暂存区。cherry-pick描述,给定一个或多个现有提交,应用每个提交引入的更改,为每个提交记录一个新的提交。这要求您的工作树是干净的(没有从头开始进行的修改)。复制提交的提交并将新提交应用于分支。应用场景commit已经提交了,为什么还要复制新的呢?应用场景一:有时版本的一些优化需求开发到一半,可能其中一个开发的需求临时实现,或者某些原因导致待开发的需求卡住,开发的需求上线。这时候就需要将commit提取出来单独处理。应用场景二:有时开发分支的代码记录被污染,导致开发分支合并到线上分支出现问题。这时候就需要拉一个干净的开发分支,然后将commit从旧的开发分支复制到新的分支。该命令使用复制单个。现在有一个feature分支,commit记录如下:需要将b复制到另一个分支,先复制commitHash,再切到master分支。当前master的最新记录是a,使用cherry-pick将b应用到当前分支。完成后查看最新的日志,b已经作为最新的commit应用到master上了。可以看到commitHash和之前的不一样了,但是commit的时间还是和之前一样的。上面复制多个是对单个提交的复制,让我们看看如何挑选多个提交。一次传输多个提交:gitcherry-pickcommit1commit2上面的命令将提交commit1和commit2应用到当前分支。也可以区间复制多个连续的commit:gitcherry-pickcommit1^..commit2上面命令将commit1到commit2区间的commit应用到当前分支(包括commit1和commit2),commit1是最早的commit。Cherry-pick代码冲突Cherry-pick多次提交时,可能会遇到代码冲突。这时候cherry-pick就会停止,让用户决定如何继续操作。让我们看看如何解决这种情况。它仍然是一个特性分支,现在我们需要将c、d、e复制到master分支。先记下起点c和终点e的commitHash。切换到master分支并使用intervalcherry-pick。可以看到c已经复制成功,到d的时候发现代码冲突,中断了cherry-pick。这时候需要解决代码冲突,重新提交到暂存区。然后使用cherry-pick--continue让cherry-pick继续。最后把e也复制进来,整个过程就完成了。以上是一个完整的过程,但是有时候代码冲突后可能需要放弃或者退出这个过程:.退出cherry-pick:gitcherry-pick--quit没有恢复到运行前的状态。即保留cherry-pick成功的commit,退出cherry-pick过程。revert描述给定的一个或多个现有提交,还原相关提交引入的更改,并记录这些更改的一些新提交。这要求您的工作树是干净的(头部没有修改)。还原现有提交,还原提交,并生成还原记录。应用场景应用场景:有一天测试人员突然告诉你,你开发上线的功能有问题,需要马上撤回,否则会影响系统的使用。这时候你可能会想到用reset来回滚,但是如果你看分支上最新的commit和其他同事的代码,用reset也会把这部分代码撤掉。因为情况紧急想不出好办法,还是任性的用reset,然后找同事重新组合他的代码(同事听说你要打人),于是你的技术形象一落千丈你同事的眼睛。命令使用revert普通提交学会revert后,就可以立马挽救这种尴尬局面了。现在主记录如下:gitrevert21dcd937fe555f58841b17466a99118deb489212还原自己提交的commit。因为revert会生成一条新的提交记录,所以此时会要求你编辑提交信息。编辑完成后,:wq保存退出。再看最新的日志,有revert记录生成。虽然你之前的提交记录还会保留,但是你修改的代码内容已经被撤回。revert合并提交在git的commit记录中,还有一种合并提交。如果要还原合并提交,用法会有点不同。master分支中现在有更多的合并提交。同样使用刚才的revert方法,你会发现命令行报错。为什么?官方文档中有解释。通常你不能恢复合并,因为你不知道合并的哪一边应该被认为是主线。此选项指定主线的父编号(从1开始)并允许revert以反转相对于指定父编号的更改。我的理解是mergecommit是两个分支的交集节点,git不知道哪个分支需要撤销,需要加参数-m指定主线分支,保留主线分支的代码,另一个将被撤销。-m后面跟一个母号来标识“主线”,一般用1来预留主支线代号。gitrevert-m1
