git 創建遠程分支和刪除 master 分支


.

.

.

.

.

最近需要將不同的客戶的代碼分開管理,所以需要為這些代碼分別創建分支。

目前版本庫中分支結構如下:

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

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

其它客戶則以 masger 分支為基礎版本創建。

大致需求的流程如下:

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM