如何使用‘ git rebase-i’重新设置分支中的所有更改的基础?

这里有一个例子:

>git status
# On branch master
nothing to commit (working directory clean)
>git checkout -b test-branch
>vi test.c
>git add test.c
>git commit -m "modified test.c"
>vi README
>git add README
>git commit -m "modified README"

现在我想做一个‘ git rebase -i’,它将让我重新调整这个分支的所有提交的基础。是否有类似于“ git rebase -i HEAD~MASTER”或类似的东西。我认为我可以做“ git rebase -i HEAD~2”,但我真的不想计算有多少提交已经作出。我也可以使用‘ git rebase -i sha1’,但是我不想梳理 git 日志来找到第一个提交 sha1。有什么想法吗?

68572 次浏览

你试过 git rebase -i master吗?

在其他平台上使用 gitk (* nix)或 gitx (OS X)或类似的工具,并查看哪个提交是您的分支的根。然后跑:

git rebase -i <the SHA hash of the root commit>

例如,我使用 gitx 检查了一个存储库:

gitx screencap

现在我知道了根散列,我可以运行这个:

git rebase -i 38965ed29d89a4136e47b688ca10b522b6bc335f

然后我的编辑突然出现,我可以随心所欲地重新排列/压扁/任何东西。

pick 50b2cff File 1 changes.
pick 345df08 File 2 changes.
pick 9894931 File 3 changes.
pick 9a62b92 File 4 changes.
pick 640b1f8 File 5 changes.
pick 1c437f7 File 6 changes.
pick b014597 File 7 changes.
pick b1f52bc File 8 changes.
pick 40ae0fc File 9 changes.


# Rebase 38965ed..40ae0fc onto 38965ed
#
# Commands:
#  pick = use commit
#  edit = use commit, but stop for amending
#  squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

我确信有一些神奇的方法可以说服 git 自动找出树的根,但我不知道它是什么。

编辑: 这个魔法是这样的:

git log master..other_feature | cat

它将向您显示该分支上的所有提交,并且通过管道传送到 cat 将禁用寻呼程序,因此您将立即看到第一个提交。

编辑: 结合以上提供了一个完全自动化的解决方案:

git rebase -i  `git log master..other_feature --pretty=format:"%h" | tail -n 1`~

好的,我假设这个分支叫做“功能”,它是从“主人”分支出来的。

有一个小小的 git 命令叫做 merge-base。它需要两次提交,并为您提供两者的第一个共同祖先。那么..。

git merge-base feature master

会给你这两个承诺的第一个共同祖先。猜猜当你传递给 git rebase 提交时会发生什么。

git rebase -i `git merge-base feature master`

来自主分支和特性分支的第一个共同祖先的交互式 rebase。 利润

一个通用的解决方案(如果您不知道上游分支的名称)是:

git rebase -i @{upstream}

请注意,如果您的上游(可能是一个跟踪分支)已经更新,因为您上次重新定位,您将拉入新的提交从上游。如果不想引入新的提交,请使用

git rebase -i `git merge-base --all HEAD @{upstream}`

不过有点拗口。

git rebase -i --onto @{u}... @{u}

从 HEAD 及其上游的单个合并点开始的交互式重建,包括 HEAD 中不在其上游的所有提交。

换句话说,就是你想要的。

自从 Gitv1.7.10以来,您只需运行 git rebase而不需要参数,它就会找到分叉点并将您的本地更改重新基于上游分支。

您需要配置上游分支才能正常工作(例如,没有参数的 git pull应该正常工作)。

有关详细信息,请参阅 Git rebase的文档:

如果未指定,则在 分支. . 远程和分支. . 合并选项将被使用(参见 Git-config [1]查看详细信息) ,并假定使用—— fork-point 选项 您当前不在任何分支上,或者如果当前分支不在 有一个配置的上游,重建基地将中止。

所有提供的解决方案的问题在于,它们不允许您从第一次提交开始就重新定基。 如果第一个提交散列是 XYZ,并且您做到了:

git rebase -i XYZ

您只能从第二次提交开始重新定基。

如果你想从第一次提交开始重新定基,你可以这样做:

git rebase -i --root

据我所知,这是观察所的问题

如果您实际上并不想在 master 上重新建立基础,但是您宁愿将所有提交压缩为一个提交,因为这与 master 不同。

从不同的分支重定基的问题

git rebase -i master的问题在于,您可能会有合并冲突,而您现在并不一定想要处理这些冲突,或者您可能在一次提交中修复了一个冲突,但是在重建过程中又在另一次提交中修复了它。

从已知提交重定基的问题

这里的整个问题是你必须使用 知道来提交,你必须引用它的 SHA,或者 HEAD ~ x,等等。这只是一个小麻烦,但它是一个烦恼。

更好的办法

如果您想要重新设置当前分支中的所有提交的基础,因为最近的提交与其父分支共享,您可以将以下别名添加到。Gitconfig:

rbi = !sh -c \"git rebase -i `git merge-base $1 HEAD`\" -

用法

git rbi parentBranch

然后,您可以使用交互式 rebase 来选择/reword/edit/squash/etc 分支中的所有提交,因为它与父分支不同。我的典型流程是选择最早的提交(位于顶部的提交) ,并将所有其他提交设置为 f (或 fixup)。

它是如何工作的

这个别名只是一个 shell 脚本,它使用了一个引用父分支的参数。该参数被传递到 git merge-base中,以确定该分支与当前分支之间最近的共享提交。