Git - 如何使用当前索引(当前状态)中的一些非暂存更改来编辑旧(不是之前的)提交?

时间:2012-12-14 00:14:12

标签: git

我已经看过这些先前的问题了:

他们并没有完全解决特定问题 - 索引中还有其他变化!运行rebase命令时,git会抱怨:Cannot rebase: You have unstaged changes.

情境:

最后一个之前的提交(我将其称为“2 HEADs前”吗?)是一个重构提交。我目前在索引中有许多非分段更改,但我只想将其中一些更改添加到上一次提交。

我想象的方法是:

  1. stash我目前的所有更改
  2. rebase -i到最后一次提交(更改索引并移动Head,对吗?)
  3. 将存储加载到我的索引中而不更改Head(如何?)
  4. 使用add -pcommit --amend有选择地修改此旧提交
  5. rebase --continue完成(更新孩子,移动回到我开始的地方,索引会发生什么?)
  6. 然后弹出/清除存储(索引回到我开始的地方)。
  7. 这是对的吗?如果是,我该如何做第3步?如果不是,我应该做什么呢?

    另外,请注意我还在学习git,我仍然不能100%确定我正在使用git(Head,index,stash等)正确引用内容。


    解决方案:

    对于其他任何可能有帮助的人,这些是我实际采取的步骤:

    1. git stash我目前的所有更改
    2. git rebase -i <ID>到上一次提交的,更改索引并移动Head
    3. git stash apply将存储加载到我的索引中而不更改Head
      • 如果您遇到冲突,请git reset HEAD <file>卸载文件暂存。确保分期清晰。
    4. 使用add -pcommit --amend有选择地进行更改并提交
    5. git reset --hard放弃索引,使其与Head
    6. 匹配
    7. git rebase --continue完成。更新孩子,移动头回到最开始,但有变化
      • 历史现在分为两个版本。另一个分支在之前隐藏的WIP结束
    8. 然后弹出存储,将索引带回我开始的地方。另一个分支也被清除。

4 个答案:

答案 0 :(得分:5)

使用git1.8.4 (July 2013),您可以选择:

  • 变基
  • 同时保留您当地的非分期更改!
  

git rebase”学习了“--[no-]autostash”选项来保存本地更改,而不是拒绝运行(人们正常的响应是将其存储并重新运行)。

因此,在您的情况下,这可以起作用(并在此期间保存您正在进行的工作):

git rebase --autostash -i <ID>

请参阅commit 587947750bd73544a6a99811f0ddfd64e1ff1445

  

此新功能允许在脏工作树或索引上执行rebase   它的工作原理是在工作树和索引更改之外创建临时“悬空合并提交”(通过'git stash create'),并在成功重组或中止后自动应用它。

     

rebase将临时合并提交的SHA-1十六进​​制以及其余的rebase状态存储在.git/{rebase-merge,rebase-apply}/autostash中,具体取决于rebase的类型。
  由于$state_dir会在成功的rebase或abort结束时自动删除,autostash也是如此。

     

这种方法的优点是我们不会影响正常存储的reflog,使autostash对最终用户不可见。
  这意味着您可以像往常一样在rebase期间使用'git stash'。

     

autostash应用程序导致冲突时,我们会将$state_dir/autostash推送到正常藏匿处,然后移除$state_dir结束rebase。   用户可以随时检查藏匿物,然后弹出或放下。


注意:git 2.0.1(Jult 25th,2014)处理自动转发情况。
请参阅commit e4244eb中的Ramkumar Ramachandra (artagnon)(也在his blog中):

rebase -i:使用autostash

处理“无所事事”的情况
  

当用户调用

$ git rebase -i @~3
  

打开脏文件并rebase.autostash,并使用空缓冲区退出$EDITOR,自动转发无法应用。

     

虽然rr / rebase-autostash的主要焦点是让git-rebase--backend.sh脚本将控制权返还给git-rebase.sh,但它在git-rebase--interactive.sh中错过了这种情况。
  由于此案例不同于其他返回内务管理控制的情况,因此请为其指定一个特殊的返回状态,并在git-rebase.sh中明确处理该值。


使用最新的git,只需执行git config rebase.autostash true即可使rebase [-i]在脏工作区中工作。

  

此新功能允许在脏工作树或索引上执行rebase   它的工作原理是在工作树和索引更改之外创建临时“悬空合并提交”(通过“git stash create”),并在成功重组或中止后自动应用它。

     

rebase将临时合并提交的SHA-1十六进​​制以及其余的rebase状态存储在.git/{rebase-merge,rebase-apply}/autostash中,具体取决于rebase的类型。由于$state_dir会在成功的rebase或abort结束时自动删除,autostash也是如此。

     

这种方法的优点是我们不会影响正常存储的reflog,使自动转发对最终用户不可见。这意味着您可以像往常一样在rebase期间使用“git stash”。

答案 1 :(得分:4)

如果我理解你想要做什么,它与第一个链接上的答案没什么不同,你只需要隐藏你不想想要添加到旧提交的更改。你可以这样做:

  1. 提交您想要添加到倒数第二次提交的更改。只需给它一个简单的提交消息,比如“添加这个”,因为它不会存在很长时间。
  2. 存储您不希望添加到提交中的其余更改。
  3. 查找您要添加的提交的。例如,如果您要修改的提交的SHA1为aaaaaaa且其父级为bbbbbbb,则您需要bbbbbbb
  4. 执行git rebase -i bbbbbbb(替换步骤3中确定的正确提交)。将最近的提交(“添加此内容”)移到您正在修改的提交的下方,并将其从pick更改为fixup。这将把它添加到该提交而不更改提交的消息。
  5. 取消暂停步骤1中的更改​​,然后从中执行更改。

答案 2 :(得分:3)

你的计划听起来不错。 git stash applygit stash pop将修改工作树和/或索引,但不会更改HEAD,因此您应该能够在rebase编辑中执行此操作。

答案 3 :(得分:0)

`git stash`
`git checkout <COMMIT HASH from 2 commits ago>`
`git stash pop`
`git add` (selectively--one file at a time)
`git commit --amend`
`git stash` (to re-stash all the changes you didn't commit)
`git branch temp`
`git checkout master`
`git rebase temp -i`

这将打开一个带有提交列表的文本编辑器 - 每行一次提交。删除第一行,即要替换的旧提交。保存并关闭。

`git branch -d temp` (to clean up the branch you created)