我创建了一个本地分支(git checkout -b
),在其中进行了一些肮脏的提交(“WIP”等)。我从来没有推过 Remote 。我现在想在推送之前重命名/压缩一些提交:
$ git rebase -i
There is no tracking information for the current branch.
Please specify which branch you want to rebase against.
See git-rebase(1) for details
git rebase <branch>
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream-to=origin/<branch> feature/position-preview
然后,我按照建议做:
$ git branch --set-upstream-to=origin/feature/my-feature feature/my-feature
error: the requested upstream branch 'origin/position-preview' does not exist
hint:
hint: If you are planning on basing your work on an upstream
hint: branch that already exists at the remote, you may need to
hint: run "git fetch" to retrieve it.
hint:
hint: If you are planning to push out a new local branch that
hint: will track its remote counterpart, you may want to use
hint: "git push -u" to set the upstream config as you push.
问题是,我不想按原样使用
push -u
,因为这会导致不良的历史记录。如何重新建立新的本地分支机构?
最佳答案
Git的文档是much的主题derision ...有充分的理由:
git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] [<upstream> [<branch>]]
这里的参数标记为
upstream
,命令的有用(?)输出涉及git branch --set-upstream-to
和origin/<branch>
,这意味着您的本地分支必须有一个类似于origin/my-feature
的远程分支才能起作用。但是,事实并非如此。git rebase
的作用是复制一系列提交,每次复制的发生就像您要在一个特定提交上运行git cherry-pick
一样。我认为,通过复制提交图中某个提交的线性提交链中的每个提交,您将获得复制开发分支的效果。1这更倾向于以图形形式表示。例如,假设您具有以下顺序:... <- o <- A <- B <-- master
\
C <- D <- E <-- my-feature
其中每个字母代表某个特定的提交(这些丑陋的40个字符的SHA-1数字之一),并且
my-feature
的提交历史与master
的提交历史在commit o
处合并在一起。如果您在my-feature
上创建了一个新的master
分支,然后返回到master
分支,进行了两次提交,然后转到my-feature
进行了三次提交(您每次提交的实际顺序),就会得到这种图没关系:我只需要您在master
上创建两个,然后就将它们绘制为第一类A
和第二个B
,并在my-feature
上绘制三个。现在,随着开发的进行,您可能会决定,根据
C
的当前提示,通过E
到master
更加有意义,即让C
的父提交为B
。实现此目的的一种非常手动的方法是:
$ git checkout master
$ git checkout -b new-my-feature
$ git cherry-pick <id of commit C>
$ git cherry-pick <id of commit D>
$ git cherry-pick <id of commit E>
这将创建一个新的分支
new-my-feature
,并复制三个commit2,结果如下: C' - D' - E' <-- new-my-feature
/
... o - A - B <-- master
\
C - D - E <-- my-feature
git构造新提交
C'
的方法是将C
的树(关联的源快照)与其父提交o
的树进行比较,将相同的更改应用于B
的树,并进行新的提交以重新使用提交消息用于C
。换句话说,commit C'
是C
的“副本”。 D'
中的D
和E'
中的E
也是如此。无论如何,如果您拍摄了第三张照片,然后删除了
my-feature
分支标签,并将new-my-feature
重命名为my-feature
,您将得到: C' - D' - E' <-- my-feature
/
... o - A - B <-- master
在旧
my-feature
上的原始三个提交是“丢失的”(它们通过“reflog”条目保存了30天,但通常不可见,以避免使 View 混乱)。git rebase
所做的是使该过程自动化:它找到要复制的提交序列,将序列复制到其他提交中,然后移动分支标签。您可以使用所有未很好说明的选项来指定分支名称(默认名称是当前分支),并且通常在某种程度上是间接的停止复制的位置。重新命名为
--onto <newbase>
的“目标”提交默认为您为重新命名为<upstream>
的内容提供的参数(如果有)。这种工作方式取决于对其他相当重要的东西的理解,这会影响两点表示法。
在进行任何选择和分支标签移动之前,让我们再次回到原始图,即重新设置基准之前的内容:
... - o - A - B <-- master
\
C - D - E <-- my-feature
现在,让我们问一下gitt_code中有哪些修订版本:
$ git rev-list master..my-feature
e59f6c2d348d465e3147b11098126d3965686098
8413a79e67177d026d2d8e1ac66451b80bb25d62
1f9e0a53489aaca7859722e037a47e93858cbc42
(我做了这些,但实际上,使用此设置,您实际上只会得到三个SHA-1)。
我认为,解释这种现象的一种好方法是用颜色填充/突出显示(当然我不能在本文中做到这一点,因此您必须想象一下)。
假设您从
master..my-feature
的技巧开始,即commit my-feature
。将此提交涂成绿色:这是“要使用”。然后,跟随其父指针返回E
。将此提交也涂成绿色。按照它的D
并将其涂成绿色;遵循它来C
并将其也涂成绿色,并在整个图形中一直到o
的父级。然后,从
o
的技巧开始,即,提交master
。将此提交涂成红色:“停止”。然后,跟随其父节点提交B
,并将其涂成红色。将其跟随到A
,并在绿色涂料上涂上红色涂料:“停止”。始终遵循o
的父母,用红色油漆覆盖其所有绿色油漆。(只要您愿意,只要不用绿色覆盖任何红色,就可以先做红色,再做绿色。)
结果-
o
应该列出的提交-正是那些(仍然)绿色的提交,这只是我们要重新设定的三个提交。即使我们从git rev-list
的提示B
提交开始“红色列表”,也是如此。所有这一切的简短形式是,为了进行基础调整,我们想要的(至少目前是这样)是
master
将git rebase
视为“上游”。用于rebase的“upstream”参数既提供“red paint”参数,又提供master
版本说明符的左半部分,并提供master..my-feature
参数:我们要复制提交,以便它们在最尖端的--onto
提交之后。实际上,您可以使用
master
将git branch --set-upstream-to
(在您自己的私有(private)存储库中)设置为master
的“上游”。上游不必像my-feature
这样的远程跟踪分支。您自己的本地分支机构在这里可以正常工作。 (但请记住,如果您确实开始共享此分支(通过将其推送到origin/branch
这样的远程git存储库中,则可能需要在那时开始使用远程跟踪分支作为“上游”)来提醒您自己可以共享,并获得更典型的基础流。您可以通过执行新的origin
随时更改“上游”。)1“分支”一词是git文档中出现问题的另一个示例。它至少具有两种不同的含义。在作为脚注的段落的一部分图中,
git branch --set-upstream-to
是一个“分支”(我喜欢称其为“分支标签”或“分支名称”)。同样,master
是一个分支。在这种情况下,这两个标签都简单标记了一个特定的提交-分别为my-feature
和B
。但是,每个提交都有自己的指向其父提交的指针:E
指向B
,A
指向E
,依此类推。遵循这些指向父母的箭头所产生的提交链也是“分支”。停止将这样的链称为“分支”的确切点取决于您的观点:
D
可能会在提交my-feature
时停止,而o
可能会继续通过master
返回。尽管这里始终没有永远正确的答案,但Git在这里并没有太大帮助:它确实取决于您要包含的内容。2有一种稍微容易些的方法,因为
o
可以将多个commit作为参数:$ git cherry-pick <id> <id> <id>
例如,或:
$ git cherry-pick my-feature~3..my-feature
它使用the gitrevisions documentation中描述的说明符获取git来找到三个ID。
关于git - Git重新建立没有远程分支的本地分支,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32831282/