git 建立远程分支和删除 master 分支

.git

.web

.xcode

.服务器

.ssh

最近须要将不一样的客户的代码分开管理,因此须要为这些代码分别建立分支。工具

目前版本库中分支结构以下:post

[yuhuashi@local:Project]$ git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/masger
remotes/origin/master网站

其中 master 分支是客户 A 所使用的分支。ui

其它客户则以 masger 分支为基础版本建立。this

大体需求的流程以下:

1.以 masger 分支做为基础为客户 B 建立分支 join。

2.将客户 A 的 master 分支重命名为 work。

修改后的分支应该以下所示:

$ git branch -a
* join
remotes/origin/HEAD -> origin/join
remotes/origin/work
remotes/origin/join
remotes/origin/masger

 

好了,叙述完了需求,那么就从头开始作起。

1.从远程仓库 clone 代码到本地,并建立本地仓库。

[yuhuashi@local:~]$ git clone ssh://user@192.168.4.9/~/proj/Project
Cloning into 'Project'...
user@192.168.4.9's password: 
remote: Counting objects: 7981, done.        
remote: Compressing objects: 100% (5962/5962), done.        
remote: Total 7981 (delta 2504), reused 6801 (delta 1784)        
Receiving objects: 100% (7981/7981), 125.27 MiB | 25.29 MiB/s, done.
Resolving deltas: 100% (2504/2504), done.
[yuhuashi@local:~]$ cd Project/
[yuhuashi@local:Project]$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/masger
  remotes/origin/master
[yuhuashi@local:Project]$

 

解释:经过 git branch -a 命令能够看到当前的分支结构。

2.建立一个空分支

[yuhuashi@local:Project]$ git checkout --orphan join
Switched to a new branch 'join'
[yuhuashi@local:Project]$ git rm -rf .
rm '.gitignore'
rm 'Project.xcodeproj/project.pbxproj'
rm 'Project/Base.lproj/LaunchScreen.xib'
rm 'Project/Base.lproj/Main.storyboard'
......
[yuhuashi@local:Project]$
[yuhuashi@local:Project]$ git branch -a
  master
  remotes/origin/HEAD -> origin/master
  remotes/origin/masger
  remotes/origin/master
[yuhuashi@local:Project]$ 

 

解释:git checkout 的时候指定 --orphan 参数能够建立一个不包含历史 log 的分支,若是使用 git branch join 会建立一个与当前分支如出一辙的叫作 join 的分支,会带着 master 分支的 log。

分支建立好以后再使用 git rm -rf . 来删除当前分支下全部被跟踪的文件。

固然,使用 checkout 建立的这个空分支使用 git branch -a 命令是看不见的,必须 commit 一次才能看见。

可是直接在这个空分支中 commit 也是不能够的(以下所示),必须在这里作一些修改才能提交。

[yuhuashi@local:Project]$ git add .
[yuhuashi@local:Project]$ git status
# On branch join
#
# Initial commit
#
nothing to commit (create/copy files and use "git add" to track)
[yuhuashi@local:Project]$ git commit -m "Initial commit"
# On branch join
#
# Initial commit
#
nothing to commit (create/copy files and use "git add" to track)
[yuhuashi@local:Project]$

 

既然 join 分支是为了客户 B 建立的,那么咱们就把客户 B 的工程拷贝到当前文件夹中。

[yuhuashi@local:~]$ cd ..
[yuhuashi@local:Project]$ git clone ssh://user@192.168.4.9/~/proj/Project b_join
Cloning into 'Project'...
user@192.168.4.9's password: 
remote: Counting objects: 8001, done.        
remote: Compressing objects: 100% (5722/5722), done.        
remote: Total 8001 (delta 2517), reused 7309 (delta 2042)        
Receiving objects: 100% (8001/8001), 125.28 MiB | 29.03 MiB/s, done.
Resolving deltas: 100% (2517/2517), done.
[yuhuashi@local:~]$ cd b_join
[yuhuashi@local:b_join]$ git checkout -b join origin/masger
Branch join set up to track remote branch join from origin.
Switched to a new branch 'join'
[yuhuashi@local:b_join]$ 

 

咱们随便找一个目录,而后把工程从新 clone 下来,这样作的目的是先把客户 B 的代码下载下来,以便拷贝到咱们刚刚为客户 B 建立的 join 分支中。

[yuhuashi@local:b_join]$ cp -r ./* ../Project/
[yuhuashi@local:b_join]$ cd ../Project

复制的时候要注意,来源路径要写成“目录名/*”,就像上面的栗子中写成了 ./*,这样不会把 ~/b_join/.git 文件夹拷贝到 ~/Project/ 目录下,覆盖掉咱们的 .git 目录。

如今咱们新建的 join 分支下已经有客户 B 的代码了,那么就能够提交这个分支了。

[yuhuashi@local:Project]$ git status
# On branch join
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#    Project.xcodeproj/
#    Project/
#    ProjectTests/
nothing added to commit but untracked files present (use "git add" to track)
[yuhuashi@local:Project]$ git add .
[yuhuashi@local:Project]$ git commit -m "Initial commit"
[join (root-commit) cf9b8d6] Initial commit
 6771 files changed, 1420915 insertions(+)
 create mode 100644 Project.xcodeproj/project.pbxproj
 create mode 100644 Project/Base.lproj/LaunchScreen.xib
 create mode 100644 Project/Base.lproj/Main.storyboard
......
[yuhuashi@local:Project]$ git branch -a
* join
  master
  remotes/origin/HEAD -> origin/master
  remotes/origin/masger
  remotes/origin/master
[yuhuashi@local:Project]$

 

git commit 以后再使用 git branch -a 就能够看到咱们建立的 join 分支了,并且使用 git log 命令查看会发现并无带有 master 分支的历史记录。 

3.建立远程分支

此时这个 join 分支还只是在咱们的本地库中,咱们得把它推送到远程库上去,这样别人才能使用它。

[yuhuashi@local:Project]$ git push origin HEAD:join
user@192.168.4.9's password: 
Counting objects: 6866, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (4910/4910), done.
Writing objects: 100% (6866/6866), 119.69 MiB | 14.84 MiB/s, done.
Total 6866 (delta 1751), reused 6811 (delta 1743)
To ssh://user@192.168.4.9/~/proj/Project
 * [new branch]      HEAD -> join
[11:12:30 yuhuashi@local:Project]$ git branch -a
* join
  master
  remotes/origin/HEAD -> origin/master
  remotes/origin/join
  remotes/origin/masger
  remotes/origin/master
[yuhuashi@local:Project]$ 

 

其实建立远程分支就是把本地分支推送到远程便可,也就是执行 git push origin HEAD:join,这样本地的 join 分支就被推送到 origin/join 了。

好了,到了这一步,咱们为客户 B 建立干净分支的目的就完成了,接下来为客户 A 把 master 分支重命名为 work。

4.重命名远程分支

重命名远程分支就是先删除远程分支,而后重命名本地分支,最后再将本地分支推送到远程库。

通常的作法以下:

删除远程分支。这种方式是推送一个空分支到远程库,其实就是删除远程分支:

git push origin :masger

重命名本地分支:

git branch -m masger develop

将本地分支推送到远程库:

git push origin HEAD:develop

可是LZ这种状况不太同样,由于要重命名的是 master 分支,master 分支是默认分支,而且别人在访问咱们的库的时候默认显示的是这个分支的内容,因此咱们不能直接删除,不然会收到一个异常:

$> git push origin :master
remote: error: By default, deleting the current branch is denied, because the next remote: error: 'git clone' won't result in any file checked out, causing confusion. remote: error: remote: error: You can set 'receive.denyDeleteCurrent' configuration variable to remote: error: 'warn' or 'ignore' in the remote repository to allow deleting the remote: error: current branch, with or without a warning message. remote: error: remote: error: To squelch this message, you can set it to 'refuse'. remote: error: refusing to delete the current branch: refs/heads/gitcafe-pages To git@gitcafe.com:ranmocy/ranmocy.git ! [remote rejected] gitcafe-pages (deletion of the current branch prohibited) error: failed to push some refs to 'git@gitcafe.com:ranmocy/ranmocy.git'
$>

解决办法就是修改默认分支为其它分支。可是应该怎么修改远程库的默认分支呢?咱们在本地操做的时候修改的都是本地分支,没法影响到远程,并且搜索出来的文章里都是用了相似 git@osc 这样的代码托管网站,能够直接在 web 页面上修改远程默认分支,以下图所示:

那么咱们本身的远程仓库应该怎样修改默认分支呢?

其实对于你本地的库来讲,被你 clone 的那个库就是远程库,而若是你在远程库里直接操做,那不就至关因而修改远程库的本地分支了吗?

因而你得先登陆到远程库的服务器上,而后在里面修改它的本地分支。

# 登陆到远程 git 库所在的服务器
[yuhuashi@local:Project]$ ssh user@192.168.4.9 # 进入远程 git 库所在的目录
[yuhuashi@local:Project]$ cd proj/Project
# 能够看到,咱们的 join 分支已经建立成功了,而且当前是在 master 分支上。并且能够看出来咱们前面的猜想没有错,在本地库看到的远程分支,其实就是远程库的本地分支。
[yuhuashi@local:Project]$ git branch -a
  join
  masger
* master
# 那么就把远程库的本地分支切换成其它分支吧。哎,为什么说这个操做只能在一个工做树中执行呢?
[yuhuashi@local:Project]$ git checkout join
fatal: This operation must be run in a work tree
# 原来这个远程库只有 git-dir,没有 wrok-tree。
# git-dir 就是 git 进行版本控制的工做空间,存放一些只有 git 才看得懂的文件,通常是 .git 文件夹,只不过 LZ 这个文件夹的名字不叫作 .git,而是与工程同名。
# work-tree 就是咱们平时工做使用的目录,也就是被 git 所控制的目录,也就是某一个分支中的内容,里面是咱们本身保存在 git 上的文件。通常是 .git 文件夹的上一级目录。
# git pull、checkout 等这些命令只能在 work-tree 中使用,而不能在 git-dir 中使用,由于它们都是用来管理 work-tree 的工具。
[yuhuashi@local:Project]$ ls
branches  config  description  HEAD  hooks  info  objects  refs
# 知道了什么缘由,那么咱们就建立一个临时的 work-tree 目录,用来切换分支。
[yuhuashi@local:Project]$ cd ..
[yuhuashi@local:proj]$ mkdir tmp
# 前面说过了,通常状况下 work-tree 和 git-dir 是放在一块儿的,也就是 work-tree 是咱们的工程目录,git-dir 是一个叫作 .git 的文件夹做为咱们工程文件夹的子目录。
# 其实 git 也提供了两个命令来分别指定当前这条命令是在哪一个 git-dir 和 work-tree 上执行,这样就可让 git 命令运行在 git-dri 与 work-tree 不在一块儿的情形了。
[yuhuashi@local:proj]$ git --git-dir=./Project --work-tree=./tmp checkout join
Checking out files: 100% (6771/6771), done.
Switched to branch 'join'
[yuhuashi@local:proj]$ cd Project/ # OK,分支已经成功切换过去了
[yuhuashi@local:Project]$ git branch -a
* join
  masger
  master
[yuhuashi@local:proj]$ rm -rf tmp
[yuhuashi@local:proj]$ exit
[yuhuashi@local:Project]$

 

如今远程默认分支已经切换成功了,咱们有两种方式继续为客户 A 建立它的 work 分支,一种就是前面第四步所说的:删掉远程分支、重命名本地分支、推送到远程分支。

另外一种方法就是以当前 master 分支为基准建立一个如出一辙的分支 work,而后删掉本地的 master 分支和远程的 origin/master 分支,而后把 work 分支推送到远程。

LZ选择了第二种方式,为何呢?由于想尝试一下删除 master 分支的方式 :)

其实删除 master 分支与删除其它远程分支的方式基本相同,惟一不一样的一点上面已经讲过了,就是在删除以前要修改一下远程库的默认分支。

好了,看看 LZ 是怎么为用户 A 建立 work 分支的吧。

(1) 建立新分支 work

[yuhuashi@local:Project]$ git branch -a
* join
  master
  remotes/origin/HEAD -> origin/master
  remotes/origin/join
  remotes/origin/masger
  remotes/origin/master
[yuhuashi@local:Project]$ git checkout master
Branch master set up to track remote branch master from origin.
Switched to a new branch 'master'
[yuhuashi@local:Project]$ git branch -a
  join
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/join
  remotes/origin/masger
  remotes/origin/master
# 用这种方式建立分支 work,会保留 master 分支的全部 log,可是不会自动切换分支到 work,因此咱们须要手动切换。
[yuhuashi@local:Project]$  git branch work
[yuhuashi@local:Project]$ git checkout work
Switched to branch 'work'
[yuhuashi@local:Project]$ 

(2)删除本地 master 分支 

[yuhuashi@local:Project]$ git branch -D master
Deleted branch master (was 0981e55).
[yuhuashi@local:Project]$

 

(3)删除远程 master 分支

[yuhuashi@local:Project]$ git push origin :master
user@192.168.4.9's password: 
To ssh://user@192.168.4.9/~/proj/Project
 - [deleted]         master
[yuhuashi@local:Project]$ git branch -a
* cruise
  join
  remotes/origin/HEAD -> origin/master
  remotes/origin/join
  remotes/origin/masger
[yuhuashi@local:Project]$

 

能够看到,通过咱们前面修改了远程的默认分支以后,如今能够直接删掉远程的 master 分支了。

(4)最后一步,将本地 work 分支推送到远程库。

[yuhuashi@local:Project]$ git push origin HEAD:work
user@192.168.4.9's password: 
Counting objects: 7172, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (4924/4924), done.
Writing objects: 100% (7115/7115), 123.00 MiB | 15.07 MiB/s, done.
Total 7115 (delta 2007), reused 7074 (delta 1970)
To ssh://user@192.168.4.9/~/proj/Project
 * [new branch]      HEAD -> work
[ yuhuashi@local:Project]$ git branch -a
* cruise
  join
  remotes/origin/HEAD -> origin/master
  remotes/origin/work
  remotes/origin/join
  remotes/origin/masger
[yuhuashi@local:Project]$

 

使用 git branch -a 能够看到,work 分支已经成功在远程库上建立了。

最后再看一下远程库的状态:

[yuhuashi@local:Project]$ git remote show origin
user@192.168.4.9's password: 
* remote origin
  Fetch URL: ssh://user@192.168.4.9/~/proj/Project
  Push  URL: ssh://user@192.168.4.9/~/proj/Project
  HEAD branch: join   # 这里代表远程库的默认分支已是 join 了
  Remote branches:
    work tracked
    join   tracked
    masger tracked
  Local refs configured for 'git push':
    cruise pushes to work (up to date)
    join   pushes to join   (up to date)
[yuhuashi@local:Project]$ git branch -a
* cruise
  join
  remotes/origin/HEAD -> origin/master   # 这里指向的分支不该该是 origin/master,而应该是 origin/join 才对。
  remotes/origin/cruise
  remotes/origin/join
  remotes/origin/masger
[yuhuashi@local:Project]$ 

 

多是由于这个库的分支已经被修改,而咱们本地库还有一些 git 数据没有与远程库同步,LZ 目前没有找到同步的办法,因此咱们先删掉这个本地库,从新从远程库 clone 一份。

[yuhuashi@local:Project]$ cd ..
[yuhuashi@local:~]$ rm -rf Project/
[yuhuashi@local:~]$ git clone ssh://user@192.168.4.9/~/proj/Project
Cloning into 'Project'...
user@192.168.4.9's password: 
remote: Counting objects: 8001, done.        
remote: Compressing objects: 100% (5722/5722), done.        
remote: Total 8001 (delta 2517), reused 7309 (delta 2042)        
Receiving objects: 100% (8001/8001), 125.28 MiB | 29.03 MiB/s, done.
Resolving deltas: 100% (2517/2517), done.
[yuhuashi@local:~]$ cd Project/
[yuhuashi@local:Project]$ git branch -a
* join
  remotes/origin/HEAD -> origin/join
  remotes/origin/cruise
  remotes/origin/join
  remotes/origin/masger
[yuhuashi@local:Project]$ git pull
user@192.168.4.9's password: 
Already up-to-date.
[yuhuashi@local:Project]$ git checkout -b work origin/work
Branch work set up to track remote branch work from origin.
Switched to a new branch 'work'
[yuhuashi@local:Project]$ git pull
user@192.168.4.9's password: 
Already up-to-date.
[yuhuashi@local:Project]$ 

 

从上面的流程可知,因为 join 已是远程库的默认分支,因此咱们 clone 了远程库以后,git 已经帮助咱们建立好 join 本地分支了。

并且从新下载的代码中,origin/HEAD 已经能够正常指向 origin/join 分支了。

 

参考文献:

Git查看、删除、重命名远程分支和tag
如何删除-Master-分支
在Git下建立一个空分支
Git系列之二 --- git-dir & work-tree

相关文章
相关标签/搜索