切换Git分支而无需文件检出


100

是否可以在Git中切换到另一个分支而不检出所有文件?

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

为了使一切变得清晰:

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

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

我知道我只能离开gh-pages分支并删除文件,但是我不喜欢脏的工作树。


您的“多久”时间有多长?您在哪个平台上工作?您是否正在通过NFS等网络进行文件共享?
Greg Hewgill

此练习的目的是什么?您是否要有两个分支,一个分支具有详细的提交,第二个分支仅记录主要更改(粗粒度)?
2009年

创建工作副本的临时(或永久?)副本可能会更便宜。我的答案相关的书面记录显示是如何工作的,即使作为主存储库的子目录。
krlmlr 2015年

Answers:


106

是的,您可以这样做。

git symbolic-ref HEAD refs/heads/otherbranch

如果您需要在该分支上提交,则也需要重置索引,否则最终将根据最后一个签出分支提交一些内容。

git reset

1
使用echo "ebff34ffb665de0694872dceabe0edeaf50ec5a9" > .git/HEAD后跟git reset指向引用而不是分支。
cadorn 2012年

1
直接写入HEAD文件的可靠性较低。如果您在子目录中怎么办?对于分离头(直接指向SHA1的头),请尝试以下操作: git update-ref HEAD refs/heads/otherbranch
Alexander Bird

2
如果要从当前分支中签出到新分支,则另一种方法是1. git stash2. git checkout -b otherBranch3.git stash pop
Winny 2014年

@AlexanderBird:git update-ref很有用,但它也可以移动当前分支的尖端。
tomekwi'2

47

仅使用基本的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

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


7
我宁愿git reset --soft <branch where you want to go>避免更新索引
JoelFan 2015年

7
我同意您的策略,避免使用git plumbing命令并偏爱瓷器命令。
user64141 '16

26

在v2.24 git switch中有点像安全的东西git checkout
因此,我将以下别名重命名git hop
“在不更改工作树的情况下在分支上跳跃”

为了读者的利益:

虽然我认为Charles Bailey的解决方案是正确的,但在切换到不是本地分支的内容时,需要对该解决方案进行调整。此外,还应该有一些易于理解的常规命令操作方法。这是我想出的:

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

解释:

  • git checkout --detachgit checkout HEAD^{}将当前分支留在后面并进入“分离头状态”相同。因此,下一个修改HEAD不再影响任何分支。分离HEAD不会影响工作树或索引。
  • git reset --soft commitish然后移动HEAD到给定的SHA commitish。如果您也想更新索引,--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别名列表中找到它。


您不想使用$@而不是$*?区别在于$ @不扩展带引号的参数,参数内部带有空格。
kyb

1
@kyb 函数技巧是从另一个SO答案中窃取的。并且$@确定地不是在这里的意思。 $*使用代替$1,从而git switch -f b变得与git switch '-f b'应该为错误的相同。这样,我就可以通过省略一些错误处理来缩短别名,例如!f() { [ 1 = $# ] || { echo 'WTF!'; return 1; }; ..
Tino

很好的解决方案。特别是,它可以用于远程分支!
Nils-o-mat

14

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

本节中有git-new-workdir工具contrib/可以帮助您。


git-new-workdir与git自己的worktree命令相同吗?当我想将分支签出到其他文件夹中时(无需克隆整个存储库),我使用工作树。
Ryuu

git-new-worktree脚本在git worktree子命令之前;编写答案时,此命令不可用。例如,该脚本需要符号链接支持。恕我直言,最好使用本机支持。
JakubNarębski17年

8

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

git read-tree分支

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

git symbolic-ref HEAD引用/头/分支

否,我只需要切换分支,无需任何其他更改-所以symbolic-ref足够好
tig

read-tree生成错误:fatal: Not a valid object name branch如果没有任何git switch branch尚未
安德里


0

拥有如此多的文件,最好保留两个存储库,每个分支一个存储库。您可以根据需要来回拉动更改。这比尝试使用git坏坏的花招要让人惊讶。


您可以git-new-worktree改用(in contrib/
JakubNarębski09年

我经常做类似的事情,就是在做任何新的“可怕的git东西”(例如更改分支等)之前,先复制本地目录。我鼓励人们沿着这条路走,直到您对自己的git-fu充满信心为止,但在可能的情况下请远离它。保留两个不同的存储库是可以的,但是会增加一层复杂性,并且不能让您利用git的许多有用功能(合并,挑选樱桃等)。
大卫,

0

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

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

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

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

git push origin c5f7eba:foo

不知道那是不是你所追求的。


:这个问题已经有了答案stackoverflow.com/questions/1282639/...
TIG

0

你可以利用

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

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


0

或者只是使用补丁文件将您的其他分支打补丁到您的主服务器

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

-1

说您想进入分支A,但要使用分支B中的文件

用git log查找分支A的当前提交引用,例如“ 99ce9a2”,

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

您现在应该位于分支A上,并且具有与B对应的文件夹结构,该文件夹结构将显示为未暂存的更改(A历史记录未更改)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.