【问题标题】:Switch Git branch without files checkout在没有文件签出的情况下切换 Git 分支
【发布时间】:2010-11-19 22:31:07
【问题描述】:

在 Git 中是否可以在不检查所有文件的情况下切换到另一个分支?

切换分支后,我需要删除所有文件,重新生成它们,提交并切换回来。所以签出文件只是浪费时间(大约有 14,000 个文件 - 这是一个很长的操作)。

为了说明一切:

我需要所有这些来将documentation 上传到 GitHub。

我有一个带有 gh-pages 分支的存储库。当我在本地重建文档时,我将其复制到存储库目录,提交并推送到 GitHub。但我并不高兴,因为我在本地有两份文档副本。我决定创建一个空分支,提交后,切换到空并删除文件。但是切换回来是一个漫长的操作——所以我问了这个问题。

我知道我可以留在 gh-pages 分支并删除文件,但我不喜欢肮脏的工作树。

【问题讨论】:

  • “长”对你来说有多长?你在哪个平台上工作?您是否在网络上工作,例如使用 NFS 或其他文件共享?
  • 这个练习的目的是什么?你想有两个分支,一个有详细的提交,第二个只记录主要的变化(粗粒度)?
  • 也许为你的工作副本创建一个临时(或永久?)克隆更便宜。 My related answerwriteup 展示了它是如何工作的,即使作为主存储库的子目录。

标签: git branch git-checkout


【解决方案1】:

是的,你可以这样做。

git symbolic-ref HEAD refs/heads/otherbranch

如果你需要在这个分支上提交,你也需要重置索引,否则你最终会根据最后签出的分支提交一些东西。

git reset

【讨论】:

  • 使用echo "ebff34ffb665de0694872dceabe0edeaf50ec5a9" > .git/HEAD 后跟git reset 来指向一个引用而不是一个分支。
  • 直接写入 HEAD 文件不太可靠。如果您在子目录中怎么办?对于分离的头部(头部直接指向 SHA1),试试这个:git update-ref HEAD refs/heads/otherbranch
  • 如果您想从当前分支签出到新分支,另一种方法是 1.git stash 2.git checkout -b otherBranch 3.git stash pop
  • @AlexanderBird: git update-ref 很有用,但它也会移动当前分支的尖端。
  • 我直接使用git reset refs/heads/otherbranch得到同样的结果
【解决方案2】:

仅使用基本的 git 命令:

这个答案比 Charles 的答案要长一点,但它只包含我能理解并因此记住的基本 git 命令,无需继续查找。

标记您当前的位置(如果需要,请先提交):

git checkout -b temp

在不改变工作目录的情况下将标记重置(移动)到另一个分支:

git reset <branch where you want to go>

现在 temp 和其他分支指向同一个提交,并且您的工作目录保持不变。

git checkout <branch where you want to go>

由于您的 HEAD 已经指向同一个提交,因此不会触及工作目录

git branch -d temp

请注意,这些命令也可以从任何图形客户端轻松获得。

【讨论】:

  • 我希望git reset --soft &lt;branch where you want to go&gt; 避免更新索引
  • 我同意您避免使用 git 管道命令并偏爱瓷器命令的策略。
【解决方案3】:

在 v2.24 中,git switch 类似于保险箱git checkout
因此我将下面的别名重命名为git hop for
“在不改变工作树的情况下跳上分支”

为了读者的利益:

虽然我认为Charles Bailey's solution 是正确的,但此解决方案在切换到某个不是本地分支时需要进行调整。还应该有一些方法可以使用易于理解的常规命令来做到这一点。这是我想出的:

git checkout --detach
git reset --soft commitish
git checkout commitish

解释:

  • git checkout --detachgit checkout HEAD^{} 相同,后者将当前分支留在后面并进入“分离头状态”。所以HEAD 的下一次修改不再影响任何分支。分离 HEAD 不会影响工作树和索引。
  • git reset --soft commitish 然后将HEAD 移动到给定commitish 的SHA。如果您也想更新索引,请离开 --soft,但我不建议这样做。同样,这不会触及工作树,并且 (--soft) 不会触及索引。
  • git checkout commitish 然后再次将HEAD 附加到给定的commitish(分支)。 (如果 commitish 是 SHA,则不会发生任何事情。)这也不会影响索引或工作树。

此解决方案接受所有涉及提交的内容,因此这对于某些 git 别名来说是理想的。下面的rev-parse 只是一个测试,以确保链中没有任何中断,这样拼写错误就不会意外切换到分离的头部状态(错误恢复会更复杂)。

这导致关注git hop treeish别名:

git config --global alias.hop '!f() { git rev-parse --verify "$*" && git checkout "HEAD^{}" && git reset --soft "$*" && git checkout "$*"; }; f'

仅供参考,您可以在我的git aliases 列表中找到它。

【讨论】:

  • 您不想使用$@ 而不是$* 吗?不同之处在于 $@ 没有扩展带引号的参数,其中有空格。
  • @kyb The function trick is stolen from another SO answer$@ 绝对不是这里的意思。使用$* 代替$1,这样git switch -f b 就与git switch '-f b' 相同,这应该是一个错误。这样我可以通过省略一些错误处理来缩短别名,例如!f() { [ 1 = $# ] || { echo 'WTF!'; return 1; }; ..
  • 非常好的解决方案。特别是它可以用于远程分支!
【解决方案4】:

拥有两个工作目录(两个工作区)和一个存储库,甚至两个存储库不是更好的解决方案吗?

contrib/ 部分中有 git-new-workdir 工具可帮助您解决此问题。

【讨论】:

  • git-new-workdir和git自带的worktree命令一样吗?当我想将分支检出到不同的文件夹时(无需克隆整个 repo),我使用 worktree。
  • git-new-worktree 脚本早于 git worktree 子命令;编写答案时,此命令不可用。例如,该脚本需要符号链接支持;恕我直言,最好使用本机支持。
【解决方案5】:

我认为您正在寻找管道命令git read-tree。这将更新索引,但不会更新工作目录中的任何文件。例如,假设branch 是要读取的分支的名称:

git read-tree 分支

如果你想提交到刚刚阅读的分支,你还需要:

git symbolic-ref HEAD refs/heads/branch

【讨论】:

  • 不,我只需要切换分支,没有任何其他更改 - 所以 symbolic-ref 就足够了
  • read-tree 生成错误:fatal: Not a valid object name branch 如果还没有任何git switch branch
  • @Andry 将branch 替换为您的目标分支名称。
【解决方案6】:

您可以使用不同的分支名称覆盖您的 HEAD 文件:

echo "ref: refs/heads/MyOtherBranch" > .git/HEAD

【讨论】:

  • 最好使用 symbolic-ref 命令为您执行此操作:git symbolic-ref HEAD refs/heads/MyOtherBranchkernel.org/pub/software/scm/git/docs/git-symbolic-ref.html
  • @GregHewgill,这是我所知道的将 HEAD 移动到提交哈希的唯一方法。你可以用git symbolic-ref 做到这一点吗?
【解决方案7】:

或者只是使用补丁文件从您的另一个分支修补到您的主分支

git diff otherbranch master > ~/tmp/otherbranch.diff
git checkout master
git apply ~/tmp/otherbranch.diff

【讨论】:

    【解决方案8】:

    有这么多文件,最好只保留两个存储库,每个分支一个。您可以根据需要来回拉取更改。这不会比试图用 git 玩坏血病的把戏更令人惊讶。

    【讨论】:

    • 您可以使用 git-new-worktree 代替(在 contrib/ 中)
    • 我经常做类似的事情,即在作为新手做任何“可怕的 git 东西”之前复制我的本地目录(比如更改分支等)。我鼓励人们走这条路,直到你对自己的 git-fu 有信心,但尽可能远离它。保留两个不同的存储库是可以的,但会增加一层复杂性,并且不会让您利用 git 的许多有用功能(合并、挑选等)。
    【解决方案9】:

    如果您只是想更改远程分支指向的位置,则可以使用“git push”来完成,而无需触及本地副本。

    http://kernel.org/pub/software/scm/git/docs/git-push.html

    参数的格式是可选的加号 +,后跟源 ref ,后跟冒号 :,后跟目标 ref 。它用于指定要更新远程存储库中的 引用的 对象。

    例如,要更新 foo 以提交 c5f7eba,请执行以下操作:

    git push origin c5f7eba:foo
    

    不确定这是不是你想要的。

    【讨论】:

    【解决方案10】:

    你可以使用

          1. git checkout -f <new-branch>
          2. git cherry-pick -x <previous-branch-commit-id>
    

    previous-branch-commit-id 是您要从中复制旧数据的提交。

    【讨论】:

      【解决方案11】:

      假设您想在分支 A 中,但使用分支 B 中的文件

      使用 git log 找到分支 A 的当前提交 ref,例如"99ce9a2",

      git checkout A
      git reset --hard B
      git reset 99ce9a2
      

      您现在应该位于分支 A,其文件夹结构对应于 B,显示为未暂存的更改(A 历史未更改)。

      【讨论】:

        猜你喜欢
        • 2010-10-03
        • 2012-08-20
        • 2012-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多