【问题标题】:Git - fastest way of committing a single change to a new branch, keeping uncommitted WIP changesGit - 将单个更改提交到新分支的最快方式,保留未提交的 WIP 更改
【发布时间】:2015-05-10 13:28:38
【问题描述】:

在开发过程中,有时我意识到我应该分开我的工作并单独提交一个小修复 - 但是,如果我有正在进行的未提交更改,并且我已经在一个有多个提交的分支上,这会变得很困难。

Git 似乎有以下选项,但都不是理想的:

  1. 将更改提交到当前分支。待未完成的更改完成并提交后,再挑选它。
  2. 克隆第二个存储库并在其中复制/粘贴更改。
  3. 存储未提交的更改。切换、编写小修复、提交、推送、切换回、unstash(似乎冗长,需要在编写之前意识到小修复需要一个单独的分支)

我想我想要类似的东西:

  1. 提交“到新分支”,指定基本提交和分支名称。这将创建一个新分支,提交更改,并可选择保留在当前分支上,包括未完成的更改,或者切换到新分支放弃未暂存的更改。

有这样的东西我可以使用吗?有没有更好的方法来完成这一切?

【问题讨论】:

  • 为什么不在提交修复之前签出一个新分支,推送然后签出到 dev 分支
  • 因为如果这些更改可能与您要切换到的内容发生冲突,您将无法切换未提交的未提交更改。
  • 对于“可能重复”的问题,答案无济于事 - 存储将存储所有未提交的更改,包括我不想移动的内容。如上所述,首先切换分支没有帮助。
  • Git 提供了所有的管道命令来实现你想要的,但你必须围绕它包装你自己的逻辑。这是可行的,但不是微不足道的。

标签: git git-branch


【解决方案1】:

我不确定我是否明白你的问题。 你有一个 git repo 并且你在current_branch。您已经进行了一些更改,并且您意识到您希望将其中的一部分提交到 new 分支上。 在这种情况下,git branch -b new_branch 将创建并切换到您的新分支而不会抱怨。只有当您切换到现有分支时,您才可能需要存储您的更改。

如果问题是您进行了更改但想在其他地方修复一些代码,那么stash 就是解决方案。

编辑:从讨论中,您似乎有一个stable 和一个current 分支,并且希望避免在稳定中弹出存储。 在这种情况下,您可能必须在新分支中提交您想要的内容,然后在 stable 中选择这个提交:

$ git checkout -b tmp_new
$ git add ... && git commit
$ git stash
$ git checkout stable
$ git checkout -b new
$ git cherry_pick tmp_new
$ git branch -d tmp_new
$ git checkout current
$ git stash pop

【讨论】:

  • 我已经进一步澄清了这个问题。我已经在一个有多个提交的分支上,不应该将其作为“新的小修复”分支的一部分推送。
  • 我不确定我是否完全理解您的问题。如果我猜对了,你在一个分支 current 上,并且你意识到你当前的一些修改可能是从其他一些分支 stable 开始提交到一个新分支 new,它不如 current 先进.本质上,您想传送一些(尚未提交的)更改,对吗?在这种情况下,您可以stash、checkout stable、checkout -b new、stash pop、add+commit、stash、checkout current。但这只是因为您的用例很复杂。
  • 你也可以checkout -b tmp_new、commit、stash。 checkout stable, checkout -b new, cherry_pick from tmp_new, branch -d tmp_new, checkout current, stash pop.
  • 正确,除了我想在current 分支上保留的一些未提交的更改,如果我将它们弹出到stable 上,则存储然后弹出它们会导致冲突。您的第二条评论确实是我认为我需要编写脚本的内容。我不认为这是一个罕见的用例,至少我的工作方式是这样。
  • 弗朗西斯,如果您想提供该命令序列作为答案,我会接受 - 它看起来是迄今为止最好的。 (我怀疑我需要编写一个 powershell 脚本来执行此操作)。
【解决方案2】:

所以你在某个分支上很热,你对你的工作树做了一个相当容易分离的修复,作为一个具体的例子,应该从 master 提交到当前分支点。

git add --patch 和边带索引你在这里介绍过吗:

git branch bugfix-62831 $(git merge-base @ master)  # commit selected changes here

bash                                            # work in an interactive subshell:

export GIT_INDEX_FILE=.git/patchworkindex       # start a(n arbitrarily-named) sideband
rm $GIT_INDEX_FILE

git read-tree bugfix-62831                      # tracking the bugfix content
git add --patch fixed.c fixed.h                 # and apply selected worktree changes

git update-ref refs/heads/bugfix-62831 $(       # update the ref with the fixed content
        git commit-tree -p bugfix-62831 -m- `git write-tree`
)

exit                                            # and we're done 

所有的索引都是一个路径名列表和与之相关的 repo 内容的 id。 Git 的 read-tree 加载索引条目。因此,当 git 查看该索引时,它会看到该提交时的路径名和内容。然后git add 从工作树中添加新内容并将索引条目指向它,add --patch 让您可以根据与已有内容的差异构建新内容。 write-tree 将索引写入 repo 并打印其顶部的 id,commit-tree 将指向该索引的提交写入 repo,update-ref 更新 ref 以指向该提交。

【讨论】:

  • 你能解释一下这里发生了什么吗?特别是使用 read-tree、commit-tree 和 write-tree。我已经阅读了文档,但并不明智!
【解决方案3】:

如果您打算在之后进行 rebase,那么最好的方法是利用 Git 故障保护机制。它也可以在没有变基的情况下工作:请参阅答案的结尾。

外壳演示

(feature) (+!) $ git commit -m "final message"
[feature shasha123] final message
...
(feature) (!) $ git stash
(feature) ($) $ git checkout main
(main) ($) $ git cherry-pick shasha123
(main) ($) $ git checkout feature
(feature) ($) $ git rebase main
warning: skipped previously applied commit shasha123
hint: use --reapply-cherry-picks to include skipped commits
hint: Disable this message with "git config advice.skippedCherryPicks false"
Successfully rebased and updated refs/head/feature.
(feature) ($) $ git stash pop
(feature) (!) $

符号含义:

  • + = 阶段性更改
  • ! = 未分阶段的更改
  • $ = 隐藏的更改

发生了什么?

  1. 我们提交了功能分支上的更改。
  2. 我们隐藏了未提交的更改并切换到主分支。
  3. 我们使用来自 git commit 的 SHA 从特性分支中挑选出提交。
  4. 我们切换回功能分支并重新基于 main。
  5. Git 阻止我们两次应用提交,从而有效地将提交移动到另一个分支。
  6. 我们弹出了存储以恢复到所需的状态。

如果我不想变基怎么办?

您仍然可以使用此方法!使用 git reset --soft HEAD^ 或 git reset --hard HEAD^ 从功能分支中删除提交,而不是变基,这取决于您是否希望在将更改移动到另一个分支后保留该分支中的更改(如果你这样做是软的,如果你不这样做是硬的't)。

【讨论】:

    猜你喜欢
    • 2018-07-17
    • 1970-01-01
    • 2016-12-20
    • 2021-05-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-04
    • 1970-01-01
    • 2010-11-24
    相关资源
    最近更新 更多