【问题标题】:Move branch pointer to different commit without checkout将分支指针移动到不同的提交而不签出
【发布时间】:2011-07-25 04:16:35
【问题描述】:

要移动已签出分支的分支指针,可以使用git reset --hard 命令。但是如何移动未签出分支的分支指针以指向不同的提交(保留所有其他内容,如跟踪的远程分支)?

【问题讨论】:

  • 听起来你想做的只是从不同的提交中创建一个分支,而不是从现在创建的提交。如果我的理解是正确的,那你为什么不简单地从你想要使用git branch <branch-name> <SHA-1-of-the-commit> 创建它的提交创建一个新分支并转储旧分支?
  • @yasouser - 我不确定转储“master”分支是个好主意。

标签: git git-branch


【解决方案1】:
git branch -f <branch-name> [<new-tip-commit>]

如果new-tip-commit 被省略,则默认为当前提交。

【讨论】:

  • 或者对于任意参考,git update-ref -m "reset: Reset &lt;branch&gt; to &lt;new commit&gt;" &lt;branch&gt; &lt;commit&gt;。 (如果你愿意,你可以挑选关于 reflog 消息的细节 - 我相信 branch -freset --hard 不同,这两者都不完全一样。)
  • Jefromi,请写一个单独的答案,以便获得投票。 :)
  • 这是一个更好的答案,因为它处理了 99% 的情况并且实际上符合文档。 git help branch 说“ -f, --force 将 重置为 如果 已经存在。没有 -f git branch 拒绝更改现有分支。”
  • 我在做git branch -f master &lt;hash&gt;,它告诉我fatal: Cannot force update the current branch. Ummmm 我现在必须做什么,在我被允许使用这个命令之前检查一些其他随机分支?
  • 如果您尝试移动的分支是您当前的分支(HEAD 指向它),这将不起作用。
【解决方案2】:

您可以对任意参考进行此操作。这是移动分支指针的方法:

git update-ref -m "reset: Reset <branch> to <new commit>" refs/heads/<branch> <commit>

-m 将一条消息添加到分支的引用日志中。

一般形式是

git update-ref -m "reset: Reset <branch> to <new commit>" <ref> <commit>

如果您愿意,您可以挑选有关 reflog 消息的细节 - 我相信 branch -freset --hard 不同,这两者都不完全一样。

【讨论】:

  • 消息的用处是什么?它存储在哪里以及以后如何读取?
  • 注意: 这不适用于裸存储库。在裸存储库上,您必须使用 'git branch -f master ' 来更新分支(请参阅下面的答案)。
  • 如果你像我一样不小心使用了 而不是 refs/heads/,你最终会在 .git/ 的 .git 目录中得到一个新文件,当您尝试使用它时,您会收到类似“refname 'master' is ambiguous”的消息。您可以从 .git 目录中删除该文件进行修复。
  • 为什么这比git branch -f更好,还没有得到满意的解释。具体来说,这种方法似乎是:(A)更难使用(B)更难记住,(C)更危险
  • “任意引用到底是什么意思” - 分支并不是唯一指向提交的引用。有标签,您也可以自己创建既不是分支也不是标签的任意 refs/whatevs/myref 样式的 ref。我相信这也回答了 Steven Lu 关于这可能是“更好”的问题。如果您使用分支,我同意 branch -f 是最简单的。
【解决方案3】:

您也可以通过git reset --hard 提交参考。

例如:

git checkout branch-name
git reset --hard new-tip-commit

我发现我经常做这样的事情:

假设这段历史

$ git log --decorate --oneline --graph
* 3daed46 (HEAD, master) New thing I shouldn't have committed to master
* a0d9687 This is the commit that I actually want to be master

# Backup my latest commit to a wip branch
$ git branch wip_doing_stuff

# Ditch that commit on this branch
$ git reset --hard HEAD^

# Now my changes are in a new branch
$ git log --decorate --oneline --graph
* 3daed46 (wip_doing_stuff) New thing I shouldn't have committed to master
* a0d9687 (HEAD, master) This is the commit that I actually want to be master

【讨论】:

  • 如果你的工作树是干净的,这很好。如果您有很多分阶段或非分阶段的更改,最好按照上面的讨论执行git update-ref
  • 您是否注意到您的“答案”并没有添加任何不属于问题的内容? ——OP说:如果是check out...可以用git reset --hard ...这里就不用重复了! :-(
  • @Robert:我不同意。问题没有说 如何 使用它,但确实如此。不用去找那个方法真是太好了。
  • @WilsonF,也许你很高兴在这里找到这个,但它根本没有回答这个问题。也许这是其他问题的答案,但这里是错误
  • 我认为这应该是对问题的评论,而不是答案。 (或者它可能是在回答问题的早期版本?)
【解决方案4】:

只是为了丰富讨论,如果您想将myBranch 分支移动到您的当前 提交,只需省略-f 之后的第二个参数

例子:

git branch -f myBranch


当我 rebase 处于 Detached HEAD 状态时,我通常会这样做:)

【讨论】:

    【解决方案5】:

    gitk --all

    • 右键单击你想要的提交
    • -> 创建新分支
    • 输入现有分支的名称
    • 确认替换该名称的旧分支的对话框上按回车键。

    请注意,重新创建而不是修改现有分支会丢失跟踪分支信息。 (对于只有一个遥控器并且您的本地分支与遥控器中的相应分支具有相同名称的简单用例,这通常不是问题。有关更多详细信息,请参阅 cmets,感谢@mbdevpl 指出这个缺点。)

    如果gitk 有一个功能,该对话框有 3 个选项:覆盖、修改现有或取消,那就太棒了。


    即使您通常像我一样是命令行迷,git guigitk 也非常适合它们允许的 git 使用子集。我强烈建议将它们用于他们擅长的事情(即有选择地在 git gui 中将大块放入/退出索引,并且也只是提交。(ctrl-s 添加签名:行,ctrl-enter 提交.)

    gitk 非常适合在您将更改整理成一个漂亮的补丁系列以提交上游时跟踪几个分支,或者在您需要跟踪多个分支的任何其他地方时分支。

    我什至没有打开图形文件浏览器,但我喜欢 gitk/git gui。

    【讨论】:

    • 这么简单!我可能刚刚从 gitg 转换为 gitk。
    • 这样一来,跟踪分支信息就丢失了。
    • @mbdevpl:我并不是真正的 git 专家。我想我明白你的意思,但不明白其中的含义。我经常使用它,并且仍然能够将这些分支推送到遥控器上的同名分支。分支与其远程跟踪分支之间的关联对您有什么作用?
    • @PeterCordes Ineed,当分支名称不匹配时,这很重要。此外,当有多个遥控器时。此外,当您使用 git prompt 显示分支状态时,它会显示到您的跟踪分支的提交距离(如果已设置)。此外,git status 输出也会受到影响。此外,在某些情况下,如果您不设置跟踪分支,git fetchgit push 将无法在不明确指定远程的情况下工作。我不知道所有案例,但对我来说,一般的经验法则是,为了方便和工作速度,最好按顺序设置跟踪分支。
    【解决方案6】:

    老实说,我很惊讶没有人想到git push 命令:

    git push -f . <destination>:<branch>
    

    点 ( . ) 指的是本地存储库,您可能需要 -f 选项,因为目标可能在“在其远程副本之后”

    虽然此命令用于将更改保存在服务器中,但结果与将远程分支 (&lt;branch&gt;) 移动到与本地分支 (&lt;destination&gt;) 相同的提交完全相同

    【讨论】:

    • 您也可以不使用-f 来执行此操作,以避免破坏本地任何内容;例如,git fetch origin &amp;&amp; git push . origin/develop:developgit checkout develop &amp;&amp; git pull --ff-only 的无需结帐的快速失败版本
    【解决方案7】:

    TortoiseGit 中的recommended solution git branch -f branch-pointer-to-move new-pointer

    • “Git 显示日志”
    • 选中“所有分支”
    • 在您希望分支指针移动到的行上(新指针):
      • 右键单击“在此版本创建分支”
      • 在“Branch”旁边,输入要移动的分支的名称(branch-pointer-to-move)
      • 在“Base On”下,检查新指针是否正确
      • 勾选“强制”
      • 好的

    【讨论】:

      【解决方案8】:

      打开文件.git/refs/heads/&lt;your_branch_name&gt;,并将其中存储的哈希更改为您想要移动分支头部的哈希值。只需使用任何文本编辑器编辑并保存文件。只需确保要修改的分支不是当前活动的分支。

      免责声明:可能不是一个可取的方法,但可以完成工作。

      【讨论】:

      • 不确定这是混乱还是邪恶的做法。 ??
      • @KeithRussell 可能两者兼有:P
      • @KeithRussell, @G 只是混乱,除非你在搞乱公共回购! :-) 从某种意义上说,这是一种受支持的方式,因为 git 文档非常详细地描述了它的内部工作原理。能够了解哪些文件是如何更新的,例如git commit 是使用 git 而不是 mercurial 的最令人信服的理由。
      【解决方案9】:

      Git 2.23.0 引入了git-switch 命令,也可用于执行此操作。

      git switch -C <branch-name> [<start-point>]
      

      -C(大写 C)选项表示如果&lt;branch-name&gt; 已经存在,则将其重置为&lt;start-point&gt;

      使用-c(小写C)它会尝试创建一个新分支,但如果已经存在则失败。

      &lt;start-point&gt; 可以是哈希、标签或其他分支名称。

      【讨论】:

        【解决方案10】:

        如果你想将一个未签出的分支移动到另一个提交,最简单的方法是运行带有 -f 选项的 git branch 命令,它决定了分支 HEAD 应该指向的位置:

        git branch -f &lt;branch-name&gt; (&lt;sha1-commit-hash&gt; or &lt;branch-name&gt;)

        例如,如果您希望本地开发分支跟踪远程(原始)开发分支:

        git branch -f develop origin/develop

        请注意,如果您尝试移动的分支是您当前的分支,这将不起作用。 要移动分支指针,请运行以下命令: git update-ref -m "reset: 重置为" refs/heads/

        git update-ref 命令安全地更新存储在 ref 中的对象名称。

        希望我的回答对你有所帮助。信息来源是this snippet

        【讨论】:

          【解决方案11】:

          对于签出的分支,如果您要指向的提交在当前分支之前(除非您想撤消当前分支的最后一次提交,否则应该是这种情况),您可以简单地执行以下操作:

          git merge --ff-only <commit>
          

          这是git reset --hard 的更柔和的替代方案,如果您不是上述情况,则会失败。

          要对未签出的分支做同样的事情,等效的应该是:

          git push . <commit>:<branch>
          

          【讨论】:

          • 问题询问如果分支未签出该怎么办。
          • 糟糕,我错过了这一点。在这种情况下,您可以按照已经建议的方式执行 git push . &lt;commit&gt;:&lt;branch&gt;
          • 这没有回答问题,因为合并创建了一个新的提交(和一个新的事态)。它不会简单地更新分支指针,除非您执行git merge --ff-only,然后只有在没有冲突的情况下。
          • @jpaugh 这就是为什么我说在你想要指向的提交在前面的情况下(我也可以精确而不是落后)。是的,如果您想确定可以使用--ff-only 选项,但该选项不会改变合并的完成方式,它只会阻止非快进合并的完成。此外,如果合并不是快进,您可以拒绝提交并使用git merge --abort 取消合并。
          • @JeanPaul 您显然是 git 专家,但您的许多读者都不是。新手不仅需要知道要使用哪个命令,还需要知道在什么上下文中使用。您的最后一条评论对此有很大帮助。但是用git merge 回答OP 的问题需要更多的命令来保护起始分支和工作树。 git stash; git checkout &lt;branch&gt;; git merge --ff-only &lt;commit&gt;; git checkout &lt;starting-branch&gt;; git pop
          猜你喜欢
          • 2011-12-24
          • 1970-01-01
          • 2016-07-29
          • 1970-01-01
          • 2011-12-17
          • 2020-11-03
          • 1970-01-01
          • 2011-04-21
          相关资源
          最近更新 更多