git - Git重新建立没有远程分支的本地分支

标签 git git-rebase

我创建了一个本地分支(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-toorigin/<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的当前提示,通过Emaster更加有意义,即让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'中的DE'中的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提交开始“红色列表”,也是如此。

所有这一切的简短形式是,为了进行基础调整,我们想要的(至少目前是这样)是mastergit rebase视为“上游”。用于rebase的“upstream”参数既提供“red paint”参数,又提供master版本说明符的左半部分,并提供master..my-feature参数:我们要复制提交,以便它们在最尖端的--onto提交之后。

实际上,您可以使用mastergit branch --set-upstream-to(在您自己的私有(private)存储库中)设置为master的“上游”。上游不必像my-feature这样的远程跟踪分支。您自己的本地分支机构在这里可以正常工作。 (但请记住,如果您确实开始共享此分支(通过将其推送到origin/branch这样的远程git存储库中,则可能需要在那时开始使用远程跟踪分支作为“上游”)来提醒您自己可以共享,并获得更典型的基础流。您可以通过执行新的origin随时更改“上游”。)

1“分支”一词是git文档中出现问题的另一个示例。它至少具有两种不同的含义。在作为脚注的段落的一部分图中,git branch --set-upstream-to是一个“分支”(我喜欢称其为“分支标签”或“分支名称”)。同样,master是一个分支。在这种情况下,这两个标签都简单标记了一个特定的提交-分别为my-featureB。但是,每个提交都有自己的指向其父提交的指针:E指向BA指向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/

相关文章:

git - 如何提取除一个文件以外的所有文件?

git - 如何将文件夹从一个 Git 存储库共享到另一个?

git - 从 git 恢复特定的提交

git - 如何在已经 rebase 的分支上 rebase

Git:移动提交 "on top"

git - 为什么我不能从我的远程分支中 pull ?

git - 将分支 merge 到 master 上的新子目录中

通过管道命令的 Git 分支状态

git describe 失败并显示 "fatal: No names found, cannot describe anything."

rebase - 如何以尽可能少的冲突将我的功能分支重新设置为 git 中的开发分支?