【问题标题】:GIT: commit changes to old/safe branch while in new/dirty/dev branch without checking out or losing unstaged dataGIT:在新/脏/开发分支中提交对旧/安全分支的更改,而不签出或丢失未暂存的数据
【发布时间】:2011-04-14 07:57:35
【问题描述】:

在我开始开发一些实验性的东西之前,我创建了一个新的分支。我通常会忘记这一点(这不是问题),但现在我提前做了。
从那时起,我更新了 3 个文件。

  • 在 2 中只是我不想提交到安全分支的实验性更改。
  • 在 1 中只是安全(次要)更改,我绝对希望将其提交到安全分支。我也可以将这些最后的更改提交到新分支(但不是)。

是否有可能 - 我确定是 - 从我的(脏)工作目录中(快速)提交一些未暂存的、未提交的更改到一个旧的、安全的分支?

我唯一能想到的就是切换分支(没有结帐),在 1 个文件中提交更改并切换回来,但我不知道切换回脏分支时更改会发生什么(是他们仍然在那里,还是因为提交而“消失”了?)...

我确信 GIT 有一些很棒的东西,但是 GIT 有这么多,我找不到完全相同的东西。
(我一直在使用this 'manual' for help,但我不确定里面是否有同样的东西。如果是(并且你愿意扫描它),请告诉我,这样我下次就知道了更难。)

谢谢!现在,我将在手边保留一张纸,其中包含“稍后提交到安全分支”的更改。

【问题讨论】:

    标签: git branch commit git-checkout


    【解决方案1】:

    无法使用 git commit 将提交添加到备用分支。有一些方法可以使用低级“管道”命令来完全按照您的描述进行操作,但是由这些命令形成的界面并不是为交互式使用而设计的1。当然有办法做你想做的事;根据您更改的详细信息和所涉及的分支的内容,它可能非常简单。

    简单案例:只需使用git checkout

    切换分支时,git checkout 将保留未提交的修改或拒绝切换(除非您使用--force--merge--conflict)。因此,只要您未提交的更改仅触及 HEAD(当前分支)和目标分支中相同的文件,git checkout 会将这些更改留在索引和/或工作树中在切换分支时。如果您未提交的更改满足此条件,那么您可以这样做:

    git checkout safe-branch
    git add -- files-with-safe-changes
    git commit
    git checkout -
    

    您还可以使用git add --patch 仅暂存和提交文件中的部分更改。

    在此之后,您的“安全更改”将成为“安全分支”的一部分;切换回原来的分支会“留下它们”(记住,git checkout 只在切换分支时保留未提交的更改)。

    如果您的其他更改依赖于“安全更改”,您可能需要将“安全分支”合并到您的工作分支中(或者,根据您的工作流程,将您的工作分支重新定位到“安全分支”的新提示)。为此,您必须隐藏未提交的更改(因为如果有未提交的更改,合并和变基都将拒绝运行)。

    git stash save
    git merge safe-branch
    git stash pop --index
    

    如果您的其他更改不依赖于“安全更改”,那么您可能不应该 麻烦合并或变基。最终,您会将这些分支合并在一起(例如,通过将它们合并到一个“qa”分支中进行预发布测试),但没有理由过早地合并它们。

    仍然很容易,但有点风险:git checkout -m

    如果第一个 git checkout 抱怨“您对 some‑file 进行了本地更改;不切换分支。”,这意味着您对some-file 进行了未提交的更改,并且该文件在“安全分支”的提示中与您当前的分支不同;您将需要一种不同的方法。

    如果您确信更改将完全适用于“安全分支”中的 some‑file 版本,那么您可以使用 -m/--merge 选项告诉 git checkout 尝试调整更改,以便它们适用于“安全分支”中的文件。如果无法干净地完成合并,那么您最终会遇到合并冲突,并且可能很难恢复您的原始更改(这就是我称之为“有风险”的原因)。

    安全:git stash + git checkout -m

    由于您确实只想将更改的子集移回“安全分支”,因此最好只关注这些更改。一种方法是使用 git stash 来临时保存您当前的更改,这样您就不必将它们全部拖回“安全分支”(然后将其中一些/大部分拖回您的工作分支)。

    git stash save
    git checkout stash -- files-with-save-changes
    git checkout -m safe-branch
    git commit
    git checkout -
    git stash pop --index
    

    其他变化是可能的。您可以使用git checkout -p stash -- files 仅选择这些文件中的一些更改。如果索引中没有分段更改,那么您可以首先分段“安全更改”git add -- files(同样,可选使用-p),使用git stash save --keep-index,切换分支(使用合并),然后提交(即用预先准备好的“安全更改”和git stash --keep-index替换git checkout stash -- files)。

    在这种情况下,我认为git checkout -m 是安全的,因为我们使用 git stash 来保存当前更改的副本;如果三路合并尝试导致一团糟,那么您可以轻松放弃将“安全更改”放在“安全分支”上的想法并重新开始工作:切换回原始分支并弹出存储( git checkout -f - && git stash pop)。

    同样,如果您的其他更改依赖于“安全更改”,那么您将需要合并或变基。您最好在弹出存储之前执行此操作(因为您需要一个干净的索引和工作树来执行合并/变基)。

    如果您不打算立即将工作分支与“安全分支”合并(或将其重新设置为基础),那么您可能希望在弹出存储库(“安全分支”)后撤消“安全更改”更改”已保存在原始存储中,您可能不希望在两个不同的分支中从头开始进行相同更改的提交2)。弹出存储后,使用 git checkout -- files-with-safe-changes 将这些文件恢复到工作分支顶端的版本。


    1 “管道”界面专为在脚本中使用而设计。直接在命令行上使用它们会很麻烦。 git commit 的早期版本(以及大多数其他 Git 命令)是基于此接口的 shell 脚本。它们今天仍然可以编写为 shell 脚本,但 C 版本通常要快得多。 提交到备用分支所需的步骤是:
    根据“安全分支”顶端的树设置备用索引,
    使用“安全”更改更新索引(如果无法干净地应用更改怎么办?最好有一个工作树来让用户解决冲突),
    将索引写为树对象,
    创建一个指向新树的新提交对象,并将“安全分支”的当前尖端作为其父级,
    更新“安全分支”引用以指向新的提交。

    2 在两个分支中提交“安全更改”在技术上没有任何问题,但确保每个更改仅源自一个地方通常是个好主意。

    【讨论】:

    • 我喜欢管道和细节。 +1
    【解决方案2】:

    由于 GIT 上的分支操作非常便宜,我将使用以下工作流程:

    • 从您的“实验”分支创建一个新分支
    • 提交所需的任何未暂存文件
    • 回到主人那里
    • cherrypick 您的“实验”提交的任何内容和刚刚在步骤 1 中创建的新分支。
    • 返回“实验”分支

    【讨论】:

      【解决方案3】:

      所以你的情况是

      x--x--x (safe)
             \
              <a,b,c> (3 private evolutions in exp branch)
      

      你想去

      x--x--x--a (a committed only in safe banch)
             \
              b,c (b and c commited in exp branch)
      

      你可以:

      git add a
      git commit -m        # in exp branch, gasp!
      git stash save       # save the rest of the exp work in progress
      git checkout master
      git merge exp        # fast-forward merge
      
      x--x--x--a (safe,exp)
                \
                 [b,c] (stashed)
      
      git branch -f exp HEAD~1  # reset branch exp to before 'a'
      git checkout exp
      git stash pop
      git add -A
      git commit -m "..."
      
      x--x--x--a (a committed only in safe banch)
            \
              b,c (b and c commited in exp branch)
      

      【讨论】:

      • 既然 checkout 不会触及修改过的文件,那不就可以checkout master; add a; commit; checkout exp 继续了吗?假设更改没有上演。
      • @rlduffy:它应该可以工作。对于这些分支开关,我总是会格外小心。
      • 如果“exp”的提交超出了“安全”(我无法从 OP 的描述中确定这一点),那么您不会想要 git checkout safe &amp;&amp; git merge exp,因为它会拉入其他提交。无论如何,如果您只是要从“exp”中删除“a”,我只会将其挑选到“安全”而不是合并它。
      • @Chris:但是摘樱桃很糟糕,不是吗?见stackoverflow.com/questions/881092/…我总是尽量避免摘樱桃。
      • @Rudie:在这种情况下,请避免使用“git branch -f exp HEAD~1”和最后的“git add, git commit”,您就会在那里。
      猜你喜欢
      • 2018-01-09
      • 1970-01-01
      • 2016-12-20
      • 2022-11-02
      • 2011-02-03
      • 1970-01-01
      • 1970-01-01
      • 2018-05-14
      • 2017-11-04
      相关资源
      最近更新 更多