糟糕,在错误的分支开发了新功能,该怎么处理呢?

image

最近在开发项目的一个小需求的时候,发生了一件尴尬的事情。那就是当我把新功能开发完成的时候,突然发现本身开发使用的分支是错误的分支。不过我记得以前学习git的时候有一个git stash的命令能够把当前没有提交的内容存档起来,而后能够在切换分支以后把当前的存档应用到目标分支。不过由于平时不怎么使用这个命令,因此有点生疏了,须要再次去看看文档。html

花了十几分钟,把git stash相关的命令又再次温习了一下,接着就顺利地把这个问题给解决掉。由于平时的开发也都是遵循相关的git流程,通常不会出现什么错误,并且平时使用的git命令也都是一些经常使用的。此次出现这个问题有一部分缘由是由于这个项目不是一个长期维护的项目,当开发新功能的时候,一打开项目,就觉得还在本身的开发分支。也没及时检查一下开发的分支是否正确。更深层次的缘由仍是由于git掌握得不够好。也正好借这个机会,把相关的命令再次好好复习一下,也挺好的git

其实当你在错误的分支开发了新功能以后,这里会有三种状况:github

  • 新功能尚未在本地进行commit(提交),也就是我此次遇到的状况
  • 新功能已经在本地提交了,可是尚未push到远程仓库
  • 新功能已经在本地提交了,且push到了远程仓库

虽然我遇到的是第一种状况,那么当我解决这个问题以后,我很天然的就会想:若是遇到了另外两种状况我该怎么处理呢?这篇文章就跟你们一块儿探讨一下针对上述三种状况下,若是你在错误的分支开发了新功能,咱们应该怎么作。segmentfault

新功能尚未在本地进行commit(提交)

在这种状况下咱们能够在当前分支下使用:app

git stash

这个命令表示把咱们当前修改的内容暂存起来,而后咱们的工做区就恢复到在没有开发新功能以前的样子。编辑器

这个时候咱们须要切换到正确的工做分支,而后运行命令:学习

git stash apply

这个命令表示把咱们以前暂存的内容,应用到当前分支。这样咱们就至关于把修改的内容从一个分支移动到了另外一个分支,是否是很简单呢。测试

上面那两个命令也是我解决这个问题中使用的命令。我以为不能知足于只解决这个问题,我须要详细的了解一下有关git stash的命令,接下来的内容是关于git stash的一些深刻的内容,咱们不只要知其然,还要知其因此然。spa

首先咱们须要知道使用git stash命令会把咱们工做区和暂存区的修改保存下来,而后将这些修改的内容从当前的文件中移出并保存在存档库里面。因此咱们就回到了以前没有修改过内容的干净的工做区。命令行

git stash在没有添加任何参数的时候至关于git stash push命令,咱们使用git stash建立一个当前修改的快照的时候,命令运行完会给出以下的信息:

Saved working directory and index state WIP on <branchname>: <hash> <commit message>

其中branchname是你当前所在分支的名字,hash是当前分支最近一次提交的hash值,commit message就是你最近的一次提交的时候添加的提交信息。

对于当前只想存储一个快照的状况下使用git stash是比较方便直观的,若是你在当前分支想存储多个快照,那么最好给每个快照添加一些解释信息,以便使用的时候可以知道每个快照都是干吗的。

咱们可使用git stash push -m message来给每个快照添加详细的说明信息,好比:

git stash push -m “add feature 1”

在这个命令行运行完成以后,在终端上会显示以下的信息:

Saved working directory and index state On <branchname>: add feature 1

根据终端显示的信息,咱们能够知道当前这个快照是在那个分支产生的,而且有了add feature 1这个详细的描述,等到之后使用的时候会更加的清楚一点。

当咱们有了不少快照的时候,咱们可能想看一下当前的快照列表。这个时候咱们能够使用git stash list来看一下当前的快照列表。在终端运行git stash list后,若是你在以前添加了一些快照的话,会显示以下的一些信息:

stash@{0}: On <branchname>: add feature 1
stash@{1}: On <branchname>: add feature 0
stash@{2}: On <branchname>: <message>
stash@{3}: WIP on <branchname>: 47e52ae <commit message>
stash@{4}: On <branchname>: <message>

从上面的信息中咱们能够知道最新的快照是排在最上面的,存储快照的是一个栈,因此最新添加的快照是放在最上面的。

若是咱们想查看最近一次快照跟生成快照当时已提交的文件之间的变化状况的话,可使用命令git stash show。这个命令默认展现的是文件的差异统计。若是想展现具体改动的内容的话,可使用git stash show -p

由于咱们有不止一个快照,因此咱们还想要看以前的快照跟产生这个快照当时已提交的版本之间的差别的话,咱们能够在上面的命令后面添加快照的索引,好比若是你想看上面add feature 0这个快照的文件变更的话,可使用下面的命令:

git stash show stash@{1} # 简略的信息
git stash show -p stash@{1} # 详细的内容更改

接下来就到了应用(恢复)快照的时候了,若是这时候你想把某个快照的内容应用于当前的分支的话,只须要运行命令:

git stash apply # 将最新的快照内容应用于当前分支
git stash apply stash@{n} # n表示具体的快照索引

这样就能够把以前保留的快照内容应用到当前的版本中了,在应用快照的过程当中可能会产生冲突,这时候须要手动把冲突的内容处理一下,而后再次提交就能够了。

git stash apply能够添加--index参数,这个参数的做用是在应用快照的时候,会把以前已经添加到暂存区(索引区)的更改依旧保存在暂存区,若是不添加这个参数的话,全部的变动都会变成在工做区的变动(也就是没有保存在索引区的状态)。

咱们能够测试一下,对一个文件进行更改,而后把更改添加(使用git add)到暂存区,而后再次添加一个更改,此次不添加到暂存区。咱们运行git status命令会看到以下的内容:

On branch dev
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   20200830/index.html

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   20200830/README.md

当咱们运行git stash命令,而后运行git stash apply命令以后,会看到以下信息:

On branch dev
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   20200830/README.md
        modified:   20200830/index.html

no changes added to commit (use "git add" and/or "git commit -a")

因此当不使用--index参数的时候,不会保存以前在暂存区的状态。

关于git stash还有一些其它的命令,好比:

  • git stash drop:丢弃一个快照
  • git stash pop:应用最新的快照到当前分支,若是应用成功的话就把这个快照从存储快照的栈中移除
  • git stash clear:清除全部的快照

关于git stash一些经常使用的命令和操做上面已经讲解的差很少啦,若是你们想继续了解更多的话,能够参考git-stash

上面的内容主要是在咱们新开发的功能尚未提交的状况下所作的一些处理,当咱们开发的新功能已经在本地提交了的状况下,咱们该如何处理呢?接下来咱们就来探讨一下这个问题。

新功能已经在本地提交了,可是尚未push到远程仓库

若是新开发的功能已经在本地提交了,可是咱们开发的这个分支是一个错误的分支。这个时候根据状况的不一样,能够有两种处理的方式。

新的功能须要添加在一个新的分支

首先咱们须要知道在咱们添加新功能以前,当前分支处于哪个提交。能够运行命令:

git log --oneline

查看当前分支的提交,能够看到有如下内容的输出:

085095f (HEAD -> master) update 5
47e52ae update 3
14fefac update 2
fd01444 add README.md
3c76ad1 init

找到咱们添加新功能时,当前分支所处的提交。假如是fd01444,那么咱们接下来要作的操做就是将HEAD指针指向fd01444,也就是把咱们当前分支已提交的内容重置到咱们开发新功能以前的样子。咱们须要运行下面的命令:

git reset fd01444 # fd01444是某次提交的hash值

若是没有指明重置的模式的话,默认会使用--mixed模式,这样的话咱们在fd01444此次提交以后的全部提交都会被重置为没有提交的状态。接下来咱们须要把这些新开发的功能迁移到一个新的分支。这时候咱们可使用下面的命令进行操做:

git checkout -b <newbranch>

这样咱们就建立了一个新的分支,而且把新添加的功能也都迁移了过去,接下来就是常规的添加和提交操做了。

新功能须要添加在另外一个分支上

若是咱们须要把当前添加的新功能迁移到另外一个已经存在的分支,那么咱们须要作的前几个步骤跟上面的操做是同样的:

git log --oneline # 查找新功能开发以前的提交
git reset <commit hash> # 将当前分支重置到新功能开发以前的提交

接下来咱们如今的状态就回到了新功能尚未提交的状态,那么就能够继续使用git stash相关的命令去操做了。

咱们还有另一个方法也可以将已提交到当前分支的功能添加到另外一个分支上,那就是使用git cherry-pick命令。首先咱们仍是先用git log --oneline查找当前已提交的功能的hash值,而后切换到目标分支,运行命令:

git cherry-pick <commit hash>

这样就把咱们在另外一个分支开发的功能,添加到咱们想要的分支了。若是有冲突的话,须要手动处理一下冲突。而后咱们回到最初的分支,再次运行git reset <commit hash>命令,把已提交的内容进行重置,而后运行命令:

git checkout -- .

把当前分支没有添加到暂存区的内容都清除掉,这样也能够达到咱们上面所说的,把新功能添加到另外一个分支的目的。

新功能已经在本地提交了,且push到了远程仓库

第三种状况就是,咱们已经把新开发的功能push到远程的仓库了,可是咱们突然发现新功能不该该在这个分支开发,咱们这个时候应该怎么办呢?

首先咱们应该保持当前的工做区是没有修改的,是一个干净的状态。否则使用撤销命令的时候会提示你须要把当前的文件内容变动先提交或者生成快照。当咱们的工做区的状态是干净的时候,咱们就能够进行撤销操做了。

首先须要知道咱们应该撤销那一次提交的状态。使用git log --oneline查看要撤销的提交的索引,而后运行下面的命令:

git revert <commit>

这个时候命令运行的终端会进入编辑器模式,让你填写提交的信息。固然你也可使用参数--no-edit这样就不会在进行撤销操做的时候打开编辑模式了。

若是须要撤销的提交比较多的话,咱们可使用..表示一个提交记录的范围。好比c1..c2就表示c2的可达提交,且排除c1的可达提交。所谓可达的提交指的是:提交自己及其祖先链中提交的集合

咱们能够举个例子:

... a - b - c - d - HEAD

若是上面表示的是某个分支的提交记录,那么对于b..d表示的就是c d这两个提交,对于a..d表示的就是b c d这三个提交。若是你们想了解更多相关的内容,能够在git-rev-list这里深刻的学习一下。

因此咱们若是想快速的撤销一段范围的提交的话,能够运行相似下面这样的命令:

git revert 54dc134..a72d612 --no-edit

上述命令的54dc134就表示c1a72d612就表示c2--no-edit代表咱们在运行撤销操做的时候不打开编辑模式。

咱们若是须要对远程的分支进行撤销的话,首先考虑的就是使用git revert命令,由于git revert命令不会修改历史的提交记录,只是在原来的提交基础上添加新的提交,因此不会形成代码的丢失。在多人合做的状况下使用git revert命令撤销push到远程的操做仍是颇有必要的。

若是你们对于上面的这些问题有更好的解决方案的话,欢迎你们在文章下面留言,咱们能够一块儿探讨一下,一块儿进步。若是你对文章有什么意见和建议的话也欢迎在文章下面留言,或者在这里提出来,我会持续努力改进的。也欢迎你们关注个人公众号关山不难越,及时获取最新的文章更新。

参考连接: