如何修改git中的指定提交?

我通常会提交一个提交列表以供审查。 如果我有:

  • HEAD
  • Commit3
  • Commit2
  • Commit1

我知道我可以使用git commit --amend修改头部提交,但是如何修改Commit1 ,因为它不是HEAD提交?

你可以使用git rebase,例如,如果你想修改回提交bbc643cd ,运行

 $ git rebase --interactive 'bbc643cd^' 

在默认编辑器中,修改要edit的提交行中的pick edit 。 进行更改,然后用与之前相同的消息进行提交:

 $ git commit --all --amend --no-edit 

修改提交,之后

 $ git rebase --continue 

返回到前面的头提交。

警告 :请注意,这将改变该提交的SHA-1 以及所有的孩子 – 换句话说,这将重写这一点的历史。 如果您使用git push --force命令进行git push --force则可以打破这个做法

使用真棒互动rebase:

 git rebase -i @~9 # Show the last 9 commits in a text editor 

find你想要的提交,把pick改为eedit ),然后保存并closures文件。 Git会回滚到提交,允许你:

  • 使用git commit --amend来进行更改,或者
  • 使用git reset @~放弃最后一次提交,而不是对文件的更改(即带你到你编辑文件但尚未提交时的位置)。

后者对于做更复杂的东西比如分裂成多个提交是有用的。

然后,运行git rebase --continue ,然后Git会在修改的提交之上重播后续的更改。 您可能会被要求解决一些合并冲突。

注意: @HEAD缩写, ~是指定提交之前的提交。

阅读更多关于在Git文档中重写历史logging的信息。

不要害怕变硬

ProTip™:不要害怕尝试重写历史logging的“危险”命令* – 默认情况下,Git不会删除90天的提交; 你可以在reflog中find它们:

 $ git reset @~3 # go back 3 commits $ git reflog c4f708b HEAD@{0}: reset: moving to @~3 2c52489 HEAD@{1}: commit: more changes 4a5246d HEAD@{2}: commit: make important changes e8571e4 HEAD@{3}: commit: make some changes ... earlier commits ... $ git reset 2c52489 ... and you're back where you started 

* 注意,像 – --hard--force这样的选项 – 他们可以丢弃数据。
另外,不要在你正在合作的分支上重写历史logging。


在很多系统上, git rebase -i会默认打开Vim。 Vim不像大多数现代文本编辑器一样工作,所以看看如何使用Vim进行重新devise 。 如果你想使用不同的编辑器,可以使用git config --global core.editor your-favorite-text-editor

使用--autosquash交互式--autosquash是我经常使用的,当我需要在历史中更深入地修正以前的提交时。 它本质上加速了ZelluX的答案所展现的过程,当您需要编辑多个提交时特别方便。

从文档:

--autosquash

当提交日志消息以“squash!…”(或“fixup!…”)开始,并且有一个标题以相同的开头的提交时,自动修改rebase -i的待办事项列表,以便提交标记为压扁之后立即提交进行修改

假设你有这样的历史:

 $ git log --graph --oneline * b42d293 Commit3 * e8adec4 Commit2 * faaf19f Commit1 

并且您有要更改为Commit2的更改,然后使用提交您的更改

 $ git commit -m "fixup! Commit2" 

或者你可以使用commit-sha而不是提交消息,所以"fixup! e8adec4甚至只是提交消息的前缀。

然后在之前的提交上启动一个交互式底图

 $ git rebase e8adec4^ -i --autosquash 

你的编辑器将打开提交已经正确的命令

 pick e8adec4 Commit2 fixup 54e1a99 fixup! Commit2 pick b42d293 Commit3 

所有你需要做的是保存并退出

跑:

$ git rebase --interactive commit_hash^

每个^表示你想要编辑的提交数量,如果它只有一个(你指定的提交哈希),那么你只需要添加一个^

使用Vim,你可以改变你想要改变的提交,保存并退出( :wq )。 然后git会提示你每次提交你标记为reword,所以你可以改变提交信息。

每个提交信息你必须保存并退出( :wq )才能进入下一个提交信息

如果您想退出而不应用更改,请按:q!

编辑 :在vim导航你使用j上去, k下去, h走左, l走右(所有这些在正常模式下,按ESC进入正常模式)。 要编辑文本,请按i以便进入插入文本的INSERT模式。 按ESC返回到正常模式:)

更新 :这是github上市的一个很好的链接如何使用git来撤销(几乎)任何东西

如果由于某种原因你不喜欢交互式编辑器,你可以使用git rebase --onto

假设你想修改Commit1 。 首先,从以前的分支Commit1

 git checkout -b amending [commit before Commit1] 

其次,用cherry-pick抓住Commit1

 git cherry-pick Commit1 

现在,修改您的更改,创buildCommit1'

 git add ... git commit --amend -m "new message for Commit1" 

最后,在隐藏其他更改之后,将其余的提交移植到新的提交之上:

 git rebase --onto amending Commit1 master 

阅读:“ amending分支, amending Commit1 (不包括)和master (包含)之间的所有提交”。 也就是Commit2和Commit3,完全删除旧的Commit1。 你可以挑选他们,但这种方式更容易。

记得清理你的分支!

 git branch -d amending 

来到这种方法(它可能是完全相同的使用交互式底座),但对我来说,这是一种直截了当的。

注意:为了说明您可以做什么而不是日常的select,我提出了这种方法。 由于它有很多步骤(可能还有一些注意事项)。

假设你想改变提交0 ,你目前在feature-branch

 some-commit---0---1---2---(feature-branch)HEAD 

结帐到这个提交并创build一个quick-branch 。 您也可以将function分支克隆为恢复点(开始之前)。

 ?(git checkout -b feature-branch-backup) git checkout 0 git checkout -b quick-branch 

你现在有这样的东西:

 0(quick-branch)HEAD---1---2---(feature-branch) 

阶段变化,藏匿一切。

 git add ./example.txt git stash 

提交更改并签出feature-branch

 git commit --amend git checkout feature-branch 

你现在有这样的东西:

 some-commit---0---1---2---(feature-branch)HEAD \ ---0'(quick-branch) 

feature-branchquick-branch (解决沿途的任何冲突)。 应用存储并删除quick-branch

 git rebase quick-branch git stash pop git branch -D quick-branch 

最后你会得到:

 some-commit---0'---1'---2'---HEAD(feature-branch) 

Git将不会重复(虽然我不能确定在什么程度上)0重新绑定时提交。

注意:所有提交散列都是从我们最初打算改变的提交开始改变的。

对我来说,这是为了从回购中删除一些凭据。 我尝试重新绑定,并在尝试重新绑定时遇到了大量看似无关的冲突 – 继续。 不要打扰企图改变自己,在mac上使用名为BFG(brew install bfg)的工具。