将选择的更改提交到另一个分支,然后恢复在当前分支上的工作?

16

在我的工作流程中经常会出现这种情况:我正在一个单独的分支上开发一个功能,但在开发过程中,我会遇到一些需要修复的小问题,这些问题可能来自框架或站点布局的更高层次。

我想要切换回主要的develop 分支,并从其中选择文件提交更改,然后返回到一个 feature 分支并进行变基(rebase),以便我可以继续处理那些与特性无关的微调/故障修复。

我正在使用 git stash 和 git stash pop 来完成这个操作,但我从一堆修改过的文件中得到了很多冲突,但这些文件实际上不需要提交给父分支。

是否有其他方法来避免冲突或以某种方式保存当前状态,并仅将选定的工作树更改拉到另一个分支以进行提交?(有点像 git-stash-cherry-pick ;-))

5个回答

15
  1. 在当前分支提交您要放在master分支上的更改。
  2. 储藏您剩余的更改。
  3. 切换到master分支,使用git cherry-pick将更改移动到master分支。
  4. 返回您的原始分支,进行rebase(可选)。
  5. 取消储藏的原始功能更改。

我运行了一个简单的测试,这个方法解决了问题。我之前对于 Git 在 rebase 时如何识别 cherry-pick 的提交而感到困惑。但它成功地从特性分支中删除了该提交,并将其移动到特性提交的下方。这正是我需要的。由于提交 sha 已更改,我只能猜测在应用主分支提交(包括 cherry-pick 的提交)后,Git 看到特性分支上的 HEAD 提交已经完成,因此不会再次应用。 - user58777
1
只是更新一下,感谢您,它运行得很好。我曾经在使用cherry-pick时遇到过冲突。由于我编辑了它以解决冲突,所以在rebase之后,git没有将相应的提交从“feature”分支的头部删除。但是我可以简单地使用git reset --hard HEAD~1来删除它。这样可以保持主分支和功能分支的线性提交历史,并且后者始终是快进的。太棒了。 - user58777
1
太好了。只是为了像我这样在第4步中不得不查找rebase部分的人:git rebase master - mplwork

3
尝试使用--merge选项切换回master分支。它将尝试在两个分支之间进行三方合并。Git文档中有一个很好的例子:
2. After working in the wrong branch, switching to the correct
   branch would be done using:

      $ git checkout mytopic

   However, your "wrong" branch and correct "mytopic" branch
   may differ in files that you have modified locally, in which 
   case the above checkout would fail like this:

      $ git checkout mytopic
      error: You have local changes to 'frotz'; not switching branches.

   You can give the -m flag to the command, which would try a
   three-way merge:

      $ git checkout -m mytopic
      Auto-merging frotz

   After this three-way merge, the local modifications are not
   registered in your index file, so git diff would show you what
   changes you made since the tip of the new branch.

是的,我有点担心使用它会导致不好的合并。但是你之前的答案很好用,而且不需要检出“脏”的工作树。这也很棒,因为你可以按照逻辑顺序提交属于主分支的小更改,当你刚刚完成它们时。 - user58777

3

通常我会反过来做。我会继续在我的特性分支上工作,直到我准备好在那里进行提交。一旦我准备好,我就会将所有属于新提交的更改添加到索引中,但不包括那些属于主干的更改。git add -p等命令使这变得非常容易。一旦索引中存在所有相关更改,我就提交给该分支。所有剩余的脏更改都属于主干,并且一旦切换到主干,这些更改会被顺利携带并进行提交。


这是一个有趣的解决方法。因为它在索引中,所以切换分支时不会出现错误? - user58777
我应该提到我喜欢使用rebase方法,因为每当我合并一个分支时,我知道不会出现冲突(功能分支始终在主分支之上,即“快进”)。这就是为什么我想将选定的更改提交到主分支,然后重新设置功能分支。我想通过输入这个来意识到,如果没有先提交更改,这是不可能发生的。只是我以前可以使用未提交的工作git checkout轻松地完成这项工作;但最近我遇到了很多错误,并且git甚至不允许我切换到另一个分支,我看不出其中的模式。 - user58777
如果您所做的脏更改不适用于您要切换到的分支,则会出现错误。但是发生这种情况的可能性似乎很小。通过差异块,通常可以确定它是否仅适用于您正在使用的功能分支,或者它是否修复了更一般的问题。如果您不再有与分支相关的更改,则通常情况下就会好转。对于大多数事情来说,这似乎是一个足够好的解决方案,特别是考虑到功能分支往往是短暂的,并且经常被反向合并到主分支上,因此超出功能范围的偏离通常是最小的。 - rafl
1
我不喜欢这个,因为它会阻止你检入“主”更改。Git 的发明就是为了解决“还没准备好检入”的综合症。 - cmcginty

2
在MacOS上,GitX使得像rafl描述的选择性提交变得非常容易,所以如果你处于这种环境中,那么这是一个很好的方法。
另外,将分支更改和主要更改分别提交到不同的提交中,然后使用git format-patch将分支中的提交导出为文件,再使用git am将它们拉入主分支,也是可行的/实用的。
但是,风险在于如果更改周围的文件过于不同,那么在将提交拉入主分支时可能会发生冲突。

2
git-gui是git自带的一部分,它以跨平台的方式提供了GUI功能。然而,使用format-patcham来将一个分支的提交应用到另一个分支似乎非常奇怪。这就是git cherry-pick的作用所在。 - rafl
GitX非常棒,我一直在使用它。确实,它有助于进行选择性提交。 - user58777

1

创建一个临时分支怎么样?

就像这样:

- oh crap need to do somethning else now
- git checkout -b ResumeLater
- git add .
- git commit
- git checkout ImportantStuff
- ....
- git checkout ResumeLater

嗨,我不认为这会奏效。我的问题是,当我在“feature”分支上开发新功能时,我已经改进或解决了“files.c”中的一个 API 调用中的错误,这使得 API 调整成为必要。现在我的分支中有 20 个修改过的文件,但我只想将 "files.c" 带回到父级 "develop" 分支。如果我 stash 和 pop,我会得到所有修改过的文件的一堆冲突。理想情况下,我需要的是 "git stash pop <file>",这样我就可以仅取出我想要提交到我的基本 "develop" 分支的文件的更改。 - user58777
我想我可以这样提交选定的更改,然后提交剩余的更改,再挑选所需的更改。但是这仍然会把选定的更改留在特性分支中。我想做的是把它们从那里拿出来,放到父分支中,并在此基础上重新定义特性分支。因此,在特性分支中只有用于特性的提交,而没有 API/框架更改等内容。我想基本上我只是想保持我的提交干净和专注。 - user58777

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接