如何在一次操作中创建功能分支并重置为 origin/master?

How to create a feature branch and reset to origin/master in a single operation?

我经常从主分支上的一个小修复开始我的旅程,最终看起来比最初想象的要复杂。

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

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

那时有人让我快速在 master 分支上做一个小改动。所以我需要创建一个 feature/bugfix 分支并将 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)

目前我用这个解决了我的问题:

$ git branch bug/foobar
$ git reset --hard origin/master
$ git checkout bug/foobar

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

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 $@"

有quicker/smarter方法吗?

据我所知,就像你说的那样,在一次操作中实现这一点的唯一方法是使用别名,但是为了进行多次操作,我个人更喜欢 bash 函数别名,基本上与 alias 相同(您在同一个文件中声明它们),但它们看起来更干净且更难以理解。例如:

yourFunction() {
    command1
    command2
      . . .
}

希望对您有所帮助。

您应该可以将 master 分支作为一个新分支签出

 $ git checkout origin/master -b feature/new_featur

编辑

上述解决方案在起作用时,将新分支设置为跟踪主分支。 (我不喜欢)

我通常在继续之前取消跟踪。

我查看了 IntelliJ 如何签出新分支,下面是如何。

$ git checkout origin/master 

在此之后,git 会告诉您您处于超然状态。现在您有了一个与 origin/master 相同的 HEAD,继续检查该提交作为一个新分支。

$ git checkout -b feature/new_feature

不要忘记git fetch

:) 魔法伤,哈?我希望它有所帮助!

重述问题

在这里,您从 master 开始,但我们可以选择任何具有上游 U[ 的起始(本地)分支 B =64=]设置。 (在你的特定情况下,上游是 origin/master。)你开始了一项你认为快速和简单的任务,现在你已经意识到它毕竟不是那么快速和容易,所以你想 "spin it off"到自己的分支。

那么我们可以观察到,我们想要的是保存当前分支的name,然后改变Git的概念"the current branch" 到一个新创建的分支,指向当前提交,然后调整保存的分支指向保存的分支的上游。

背景

分支名称只是指向某个提交的标签。 Git 在这里相当明智:git branch 允许您创建一个 new 标签指向 any 现有提交,或移动任何内容except 任何现有提交的当前分支。默认是创建指向当前提交的新分支。

棘手的部分是 当前分支 不能以这种方式移动,原因是当前分支必须匹配索引和工作树,除了任何您现在正在进行的积极更改。只有一个面向用户的 ("porcelain") 命令可以更改 Git 对 "the current branch" 的概念,即 git checkout.

幸运的是,git checkout 也有 -b(创建新分支)标志,它的操作很像 git branch:它默认在当前提交时创建一个新分支。此外,它尽可能避免触及索引和工作树——就像任何其他 git checkout 一样——所以如果我们在当前提交创建一个新分支,它永远不必触及索引或工作树全部。结果是它总是成功,并将我们留在新创建的分支上。 (它 可以 创建一个指向特定提交的新分支,但这也可能会失败——但我们在这里不需要该功能,因此我们可以使用它不需要的模式不会失败。好吧,"doesn't fail" 只要新分支名称确实 至少是新的。)

因此,解决方案

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

为了使这个脚本可靠,让我们实际检查一下我们需要的条件:我们在某个分支上(所以 HEAD 不是 "detached")并且这个分支有一个上游集合。然后我们可以创建我们的新分支并重新指向——使用 git branch -f,即不使用 git reset——另一个分支:

#! /bin/sh
#
# git-spinoff: spin the current branch off to a new
# branch.  When this succeeds, we are on the new branch.

die() {
    echo "fatal: $@" 1>&2
    exit 1
}

# check arguments
case $# in
1) newbranch="";;
*) echo "usage: git spinoff <newbranch>" 1>&2; exit 1;;
esac

# make sure we are on a branch that has an upstream
branch=$(git symbolic-ref -q --short HEAD) ||
    die "existing branch is detached; there's nothing to restore"
upstream=$(git rev-parse -q --verify @{u}) ||
    die "existing branch $branch has no upstream: there's nowhere to restore-to"

# now create and check out out the new branch, or quit if we can't
git checkout -b "$newbranch" || exit $?

# last, re-adjust the previous branch (which is no longer the current
# branch since we are on the new one we created) to point to its own
# upstream (if this fails, ignore the failure!)
git branch -f "$branch" "$upstream"

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

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

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

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