如何在单个操作中创建功能分支并重置为原点/主站?

now*_*wox 6 git git-branch

我经常以主分支上的小修复开始我的旅程,最终看起来比最初想象的更复杂.

所以我很容易陷入这种情况:

* Damned I have more stuff to check (HEAD -> master)
* Forgot to fix this as well...
* Oops, fixed that too
* Fixed this
* (origin/master)
Run Code Online (Sandbox Code Playgroud)

那时有人要我快速对主分支进行一些小改动.所以我需要创建一个feature/ bugfixbranch并恢复master到它origin:

$ git branch --magic bug/foobar
$ git log
* Damned I have more stuff to check (HEAD -> bug/foobar)
* Forgot to fix this as well...
* Oops, fixed that too
* Fixed this
* (master, origin/master)
Run Code Online (Sandbox Code Playgroud)

目前我解决了我的问题:

$ git branch bug/foobar
$ git reset --hard origin/master
$ git checkout bug/foobar
Run Code Online (Sandbox Code Playgroud)

我显然可以为它创建一个别名(尚未测试):

swap-to="!git branch $@ && \
          git reset --hard \
             \$(git config --get branch.\$(git rev-parse --abbrev-ref HEAD).remote)/\
             \$(git rev-parse --abbrev-ref HEAD) && \
          git checkout $@"
Run Code Online (Sandbox Code Playgroud)

有没有更快/更聪明的方法来做到这一点?

tor*_*rek 2

重述问题

\n\n

在这里,您从 开始master,但我们可以选择任何具有一些上游U集的起始(本地)分支B。(在您的特定情况下,上游是。)您开始执行一项您认为快速且简单的任务,现在您已经意识到它毕竟不是那么快速和容易,因此您想将其“剥离”到有自己的分支机构。origin/master

\n\n

那么我们可能会观察到,我们想要的是保存当前分支的名称,然后将 Git 的“当前分支”概念更改为新创建的分支,指向当前提交,然后调整保存的分支指向已保存分支的上游。

\n\n

背景

\n\n

分支名称只是指向某些提交的标签。Git 在这里相当明智:git branch允许您创建一个指向任何现有提交的标签,或者将当前分支之外的任何内容移动到任何现有提交。默认情况下是创建指向当前提交的新分支。

\n\n

棘手的部分是当前分支不能以这种方式移动,其原因是当前分支必须与索引和工作树匹配,除了您现在正在进行的任何活动更改之外。只有一个面向用户(“瓷器”)的命令可用于更改 Git\“当前分支”的概念,即git checkout.

\n\n

幸运的是,git checkout还有-b(创建新分支)标志,其操作非常类似于git branch:它默认在当前提交处创建一个新分支。此外,它尽可能避免接触索引和工作树\xe2\x80\x94就像任何其他git checkout\xe2\x80\x94一样,所以如果我们在当前提交创建一个新分支,它永远不必接触索引或工作- 根本没有树。结果是它总是成功,并将我们留在新创建的分支上。(它可以创建一个指向特定提交的新分支,但这也可能会失败\xe2\x80\x94,但我们在这里不需要该功能,因此我们可以使用它不会失败的模式。好吧,至少只要新分支名称确实是新的,“就不会失败”。)

\n\n

因此,解决方案

\n\n

解决方案仍然需要几行脚本,但我们可以将其编写为一个名为的小脚本git-spinoff并将其放入我们的 $PATH 中(我将用于$HOME/scripts/git-spinoff此目的)。我们甚至可以将其作为 shell 别名函数来执行,但我发现脚本总体上更好(更容易理解、调试等)。

\n\n

为了使这个脚本可靠,让我们实际检查我们所需的条件:我们位于某个分支上(因此HEAD不是“分离”)并且该分支有一个上游集。然后我们可以创建新分支并使用 重新指向 \xe2\x80\x94 git branch -f,即不使用git reset\xe2\x80\x94 另一个分支:

\n\n
#! /bin/sh\n#\n# git-spinoff: spin the current branch off to a new\n# branch.  When this succeeds, we are on the new branch.\n\ndie() {\n    echo "fatal: $@" 1>&2\n    exit 1\n}\n\n# check arguments\ncase $# in\n1) newbranch="$1";;\n*) echo "usage: git spinoff <newbranch>" 1>&2; exit 1;;\nesac\n\n# make sure we are on a branch that has an upstream\nbranch=$(git symbolic-ref -q --short HEAD) ||\n    die "existing branch is detached; there\'s nothing to restore"\nupstream=$(git rev-parse -q --verify @{u}) ||\n    die "existing branch $branch has no upstream: there\'s nowhere to restore-to"\n\n# now create and check out out the new branch, or quit if we can\'t\ngit checkout -b "$newbranch" || exit $?\n\n# last, re-adjust the previous branch (which is no longer the current\n# branch since we are on the new one we created) to point to its own\n# upstream (if this fails, ignore the failure!)\ngit branch -f "$branch" "$upstream"\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后一个命令实际上可以改进,因为有一个“管道命令”可以完成我们想要的事情。refs/heads/要使用它,我们必须保留原始分支的完整(样式)名称,并选择一条消息。这个特定的消息可能是可以改进的,因此只是一个示例:

\n\n
fullbranch=$(git symbolic-ref -q HEAD) || die ...\nbranch=${fullbranch#refs/heads/}\n... same as before ...\ngit update-ref -m \\\n    "git spinoff: re-point $branch to ${branch}@{upstream}" \\\n    $fullbranch $upstream\n
Run Code Online (Sandbox Code Playgroud)\n\n

有了这个git-spinoff脚本在我们的路径中,我们现在可以运行git spinoff.

\n\n

编辑:现在已经过测试,并包含在https://github.com/chris3torek/scripts中(如https://github.com/chris3torek/scripts/blob/master/git-spinoff)。

\n