git切换分支的命令git如何切换远程分支git切换到远程分支的命令




git切换分支的命令git如何切换远程分支git切换到远程分支的命令

2022-07-20 20:10:39 网络知识 官方管理员

作为程序员的我们应该都有一个感受,一旦进入某个项目,从开发,到发布生产,到hotfix,到后期维护,那基本都有你的份,正在开发某个feature,老板突然跳出来说让你做生产商的hotfix更是家常便饭,面对这种情况,使用Git的我们通常有两种解决方案:

  1. 草草提交未完成的feature,然后切换分支到hotfix
  2. gitstash|gitstashpop暂存工作内容,然后再切换到hotfix

第二种方式较第一种还好很多,可是面对下面这些场景,stash依旧不是很好的解决方案

git切换分支的命令(git如何切换远程分支)(1)

我们面对的场景

  1. 正在main分支上跑很长时间的测试,切换到hotfix或feature,测试就会中断
  2. 项目非常大,频繁地切换索引,成本非常高
  3. 在几年前release的旧版本,设置和当前不一样,IDErestructure适配切换也会带来很大的开销
  4. 切换分支,需要重新设置相应的环境变量,比如dev/qa/prod
  5. 需要切换到同事的代码,帮助调试代码复现问题

有的同学想到,gitclone多个repo不就可以了吗?这是解决上述问题的一个方法,但背后同样隐藏着很多问题:

  1. 多个repo的状态是不好同步的,比如没办法快速cherry-pick,一个repocheckout的分支,另外一个repo需要重新checkout
  2. githistory/log是重复的,当项目历史非常长,.git文件夹下的内容是非常占用磁盘空间的
  3. 同一个项目,多个repo,不易管理

那如何做才能满足这些特殊场景,又不出现上述这些问题呢?

git-worktree

其实,这是Git2015年前就开始支持的功能,却很少有人知道它,git-worktree的使用非常方便,在终端输入:

gitworktree--help

就可以快速看到帮助文档说明:

git切换分支的命令(git如何切换远程分支)(2)

用简单的话来解释git-worktree的作用就是:

仅需维护一个repo,又可以同时在多个branch上工作,互不影响

上面红色框线命令有很多,我们常用的其实只有下面这四个:

gitworktreeadd[-f][--detach][--checkout][--lock][-b<new-branch>]<path>[<commit-ish>]gitworktreelist[--porcelain]gitworktreeremove[-f]<worktree>gitworktreeprune[-n][-v][--expire<expire>]

在展开说明之前,需要和大家普及两个你可能忽视的Git知识点:

  1. 默认情况下,gitinit或gitclone初始化的repo,只有一个worktree,叫做mainworktree
  2. 在某一个目录下使用Git命令,当前目录下要么有.git文件夹;要么有.git文件,如果只有.git文件,里面的内容必须是指向.git文件夹的

第二句话感觉挺绕的,下面用例子说明,就很容易明白了

gitworktreeadd

当前项目目录结构是这样的(amend-crash-demo是repo的root):

.└──amend-crash-demo1directory

cdamend-crash-demo运行命令gitworktreeadd../feature/feature2

➜amend-crash-demogit:(main)gitworktreeadd../feature/feature2Preparingworktree(newbranch'feature2')HEADisnowat82b8711addmainfile

重新看目录结构

.├──amend-crash-demo└──feature└──feature23directories

该命令默认会根据HEAD所在的commit-ish(当然也可以指定gitlog中的任意一个commit-ish)创建一个名为feature2的分支,分支磁盘位置如上面结构所示

cd../feature/feature2/会发现,这个分支下并不存在.git文件夹,却存在一个.git文件,打开文件,内容如下:

gitdir:/Users/rgyb/Documents/projects/amend-crash-demo/.git/worktrees/feature2

到这里,你再理解一下上面的知识点2,是不是就清晰许多了呢?

接下来,你就可以在feature2分支上做一切你想做的内容了(add/commit/pull/push),和mainworktree互不干扰

一般情况下,项目组都有一定的分支命名规范,比如feature/JIRAID-Title,hotfix/JIRAID-Title,如果仅仅按照上面命令新建worktree,分支名称中的/会被当成文件目录来处理

gitworktreeadd../hotfix/hotfix/JIRA234-fix-naming

运行完该命令,文件目录结构是这样的

.├──amend-crash-demo├──feature│└──feature2└──hotfix└──hotfix└──JIRA234-fix-naming6directories

很显然这不是我们想要的,这时候我们就需要-b参数的支持了,就像gitcheckout-b一样

执行命令:

gitworktreeadd-b"hotfix/JIRA234-fix-naming"../hotfix/JIRA234-fix-naming

再来看一下目录结构

.├──amend-crash-demo├──feature│└──feature2└──hotfix├──JIRA234-fix-naming└──hotfix└──JIRA234-fix-naming7directories

进入JIRA234-fix-naming目录,默认是在hotfix/JIRA234-fix-naming分支上

git切换分支的命令(git如何切换远程分支)(3)

worktree建立起来很容易,不加管理,项目目录结构肯定乱糟糟,这是我们不想看到的,所以我们需要清晰地知道某个repo都建立了哪些worktree

gitworktreeadd[-f][--detach][--checkout][--lock][-b<new-branch>]<path>[<commit-ish>]gitworktreelist[--porcelain]gitworktreeremove[-f]<worktree>gitworktreeprune[-n][-v][--expire<expire>]0

所有的worktree都在共用一个repo,所以在任意一个worktree目前,都可以执行如下命令来查看worktree列表

gitworktreeadd[-f][--detach][--checkout][--lock][-b<new-branch>]<path>[<commit-ish>]gitworktreelist[--porcelain]gitworktreeremove[-f]<worktree>gitworktreeprune[-n][-v][--expire<expire>]0

执行完命令后,可以查看到我们上面创建的所有worktree信息,mainworktree也会显示在此处

gitworktreeadd[-f][--detach][--checkout][--lock][-b<new-branch>]<path>[<commit-ish>]gitworktreelist[--porcelain]gitworktreeremove[-f]<worktree>gitworktreeprune[-n][-v][--expire<expire>]1

worktree工作做完了,也是要及时删除的,否则也会浪费很多磁盘空间

gitworktreeremove

这个命令很简单了,worktree的名字叫什么,直接就remove什么就好了

gitworktreeadd[-f][--detach][--checkout][--lock][-b<new-branch>]<path>[<commit-ish>]gitworktreelist[--porcelain]gitworktreeremove[-f]<worktree>gitworktreeprune[-n][-v][--expire<expire>]2

此时,分支名弄错的那个hotfix就被删掉了

gitworktreeadd[-f][--detach][--checkout][--lock][-b<new-branch>]<path>[<commit-ish>]gitworktreelist[--porcelain]gitworktreeremove[-f]<worktree>gitworktreeprune[-n][-v][--expire<expire>]3

假设你创建一个worktree,并在里面有改动,突然间这个worktree又不需要了,此刻你按照上述命令是不能删掉了,此时就需要-f参数来帮忙了

gitworktreeadd[-f][--detach][--checkout][--lock][-b<new-branch>]<path>[<commit-ish>]gitworktreelist[--porcelain]gitworktreeremove[-f]<worktree>gitworktreeprune[-n][-v][--expire<expire>]4

删除了worktree,其实在Git的文件中,还有很多administrative文件是没有用的,为了保持清洁,我们还需要进一步清理

gitworktreeprune

这个命令就是清洁的兜底操作,可以让我们的工作始终保持整洁

总结

到这里,你应该理解,整个git-worktree使用流程就是下面这四个命令:

gitworktreeaddgitworktreeadd[-f][--detach][--checkout][--lock][-b<new-branch>]<path>[<commit-ish>]gitworktreelist[--porcelain]gitworktreeremove[-f]<worktree>gitworktreeprune[-n][-v][--expire<expire>]0gitworktreeremovegitworktreeprune

你也应该明白gitworktree和gitclone多个repo的区别了。只维护一个repo,创建多个worktree,操作间行云流水

我的实践:通常使用gitworktree,我会统一目录结构,比如feature目录下存放所有feature的worktree,hotfix目录下存放所有hotfix的worktree,这样整个磁盘目录结构不至于因为创建多个worktree而变得混乱

在磁盘管理上我有些强迫症,理想情况下,某个repo的worktree最好放在这个repo的文件目录里面,但这就会导致Gittrack新创建的worktree下面的所有文件,为了避免Gittrackworktree的内容,来来回回修改gitignore文件肯定是不合适的,

发表评论:

最近发表
网站分类
标签列表