![](/img/trans.png)
[英]Git: How to fetch a single remote branch and create a remote-tracking branch of it automatically?
[英]How to create git Remote-Tracking Branch
他們說這很簡單
您可以簡單地通過將-u標志與“ git push”一起使用來告訴Git跟蹤新創建的遠程分支。
但這對我沒有用。
如何創建git Remote-Tracking分支
Git現在可以通知您有關“未推動”和“未推動”的提交。
這是我的:
$ git status
On branch newfeature/v4-json
nothing to commit, working tree clean
與我的期望相比,引用以上文章 :
$ git status
# On branch dev
# Your branch and 'origin/dev' have diverged,
# and have 1 and 2 different commits each, respectively.
#
nothing to commit (working directory clean)
即,有關“未推動”和“未推動”提交的信息。
即,我希望看到與以下內容相同的內容:
$ git status
On branch master
Your branch is ahead of 'origin/master' by 3 commit.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
但是從上面的實際輸出中,您可以看到, 盡管我已經進行了幾次提交 , 但我仍然無法看到到目前為止我已經進行了多少次提交 。
這是我所做的:
$ git push -u origin newfeature/v4-json
Counting objects: 12, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (12/12), 1.87 KiB | 958.00 KiB/s, done.
Total 12 (delta 9), reused 0 (delta 0)
remote: Resolving deltas: 100% (9/9), completed with 9 local objects.
remote:
remote: Create a pull request for 'newfeature/v4-json' on GitHub by visiting:
remote: https://github.com/.../pull/new/newfeature/v4-json
remote:
To github.com:xxx/yyy.git
* [new branch] newfeature/v4-json -> newfeature/v4-json
Branch 'newfeature/v4-json' set up to track remote branch 'newfeature/v4-json' from 'origin' by rebasing.
但是我沒有git
從'origin'設置的遠程跟蹤分支'newfeature / v4-json':
A) git remote show origin
根本不顯示我的newfeature的遠程跟蹤分支:
$ git remote show origin
* remote origin
Fetch URL: git@github.com:go-easygen/easygen.git
Push URL: git@github.com:go-easygen/easygen.git
HEAD branch: master
Remote branch:
master tracked
Local branches configured for 'git pull':
master rebases onto remote master
newfeature/v4-json rebases onto remote newfeature/v4-json
Local refs configured for 'git push':
master pushes to master (up to date)
newfeature/v4-json pushes to newfeature/v4-json (up to date)
根據http://www.gitguys.com/topics/adding-and-removing-remote-branches ,以下是我想看到的內容
$ git remote show origin
* remote origin
Fetch URL: /tmp/.../git/rp0
Push URL: /tmp/.../git/rp0
HEAD branch: master
Remote branches:
master tracked
newfeature tracked
Local branches configured for 'git pull':
master rebases onto remote master
newfeature rebases onto remote newfeature
Local refs configured for 'git push':
master pushes to master (up to date)
newfeature pushes to newfeature (up to date)
請注意,在“ Remote branches:
部分中,除了master tracked
外,還master tracked
了一個newfeature tracked
。 根據上述文章,被跟蹤的 newfeature tracked
稱為遠程跟蹤分支 。
B) git branch -a
都不是:
$ git branch -a
master
* newfeature/v4-json
remotes/origin/HEAD -> origin/master
remotes/origin/master
那里只有一個remotes/origin/master
遠程跟蹤名稱,而我期望更多。 例如(無關緊要,只是為了顯示具有更多遠程跟蹤名稱的情況),
$ git branch -a
* master
remotes/origin/HEAD
remotes/origin/master
remotes/origin/v1.0-stable
remotes/origin/experimental
C) git branch -vv
也不是:
$ git branch -vv
master 75369c3 [origin/master] - [*] allow ...
* newfeature/v4-json 8c98d9c - [*] update ...
我希望看到,
$ git branch -vv
master 75369c3 [origin/master] - [*] allow ...
* newfeature/v4-json 8c98d9c [origin/newfeature/v4-json] - [*] update ...
此外,
git pull
也不從遠程更新我的本地分支:
$ git pull
From github.com:xxx/yyy
* branch newfeature/v4-json -> FETCH_HEAD
Already up to date.
Current branch newfeature/v4-json is up to date.
$ git pull
From github.com:xxx/yyy
* branch newfeature/v4-json -> FETCH_HEAD
Already up to date.
Current branch newfeature/v4-json is up to date.
$ git pull
From github.com:xxx/yyy
* branch newfeature/v4-json -> FETCH_HEAD
Already up to date.
Current branch newfeature/v4-json is up to date.
就是說,無論我拉多少次,我都不會得到相同的輸出,
$ git pull
Already up to date.
Current branch master is up to date.
以上都是不正常的。 我已經使用MS VS多次創建了Remote-Tracking Branch,其結果完全符合我的預期,而不是上面的預期。 但是,我不喜歡黑魔術,所以我想知道如何使用純git
來做同樣的事情。
那么創建git Remote-Tracking Branch的正確方法是什么?
編輯以更新地址( git branch -a
和git branch -vv
)輸出:是的,缺少某些內容 。 目前還不清楚到底出了什么問題,但我有一個猜測。 git push -u
輸出的這一部分:
* [new branch] newfeature/v4-json -> newfeature/v4-json Branch 'newfeature/v4-json' set up to track remote branch 'newfeature/v4-json' from 'origin' by rebasing.
顯示您的Git將您的origin/newfeature/v4-json
(分為兩部分)設置為newfeature/v4-json
上游。 但是您的git branch -a
和git branch -vv
輸出顯示不存在origin/newfeature/v4-json
。
我可以通過進行單分支克隆來重現此行為的關鍵要素。 使用git clone --depth= number
或git clone --single-branch
將產生這樣的克隆。 這樣做的副作用是,您的Git將永遠不會為任何分支創建任何遠程跟蹤名稱, 除非您告訴Git所關心的那個分支。 如果這是問題所在,則解決方法是將克隆轉換為普通(多分支)克隆。 (如果使用--depth
創建單分支方面,則取消克隆該副本也是明智的。)
要查看您的origin
克隆是否設置為單分支:
$ git config --get-all remote.origin.fetch
在普通克隆中,將打印:
+refs/heads/*:refs/remotes/origin/*
在選擇了分支master
的單分支克隆中,將打印:
+refs/heads/master:refs/remotes/origin/master
它告訴您的Git: 為master
創建一個遠程跟蹤名稱,而不是為*
(即所有分支)創建前者的遠程跟蹤名稱 。
取消origin
克隆的單分支:
$ git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
(或直接編輯.git/config
,例如git config --edit
,這是我的首選方法)。 另請參閱如何“撤消”-單分支克隆?
要將淺層克隆轉換為完整(非淺層)克隆,只需運行:
$ git fetch --unshallow
請注意,盡管git clone
默認將它們git clone --depth= number --no-single-branch
在一起,但此操作與單分支無關(您可以在git clone
時使用git clone --depth= number --no-single-branch
覆蓋此操作)。 在2.15之前的版本中,沒有針對淺薄度的命令行測試; 在2.15或更高版本中,使用:
git rev-parse --is-shallow-repository
但在此之前,您必須測試文件.git/shallow
的存在:
if [ -f $(git rev-parse --git-dir)/shallow ]; then
echo true
else
echo false
fi
模擬git rev-parse --is-shallow-repository
。
順便說一句,您要查看的輸出存在問題。 您說您想將newfeature
看作是遠程服務器上的一個分支,但這不會發生,因為需要存在newfeature/v4-json
名稱,這排除了newfeature
的存在能力。
(以下行的原始答案。)
$ git push -u origin newfeature/v4-json
這完全按照您的要求進行。 在您顯示的其余輸出中,一切都很好。 因此,尚不清楚您認為錯在哪里; 其實沒有錯。 我將解決您顯示的其他消息:
# Your branch and 'origin/dev' have diverged, # and have 1 and 2 different commits each, respectively.
下面。
回顧一下Git的工作方式和一些Git特有的術語可能會有所幫助。 我認為,特別是,您使用的短語- 遠程跟蹤分支 -是一個壞詞,會引起誤解。 這是一個Git術語,所以我們應該理解人們在使用它時的含義,但這是一個不好的術語,這意味着人們會濫用它,如果您對某人的使用感到困惑,那么可能應該退一步並考慮一下這些事情再次發生。
首先,讓我們注意Git實際上就是關於commit的全部內容。 承諾是Git的存在理由 ; 沒有提交,我們根本不會使用Git。 因此,讓我們看看什么是提交。
每個提交都包含文件,但不僅僅是一組文件。 它是快照中所有文件的快照, 1但它也包含一些元數據: 有關存儲數據的信息。 最明顯的是您在git log
輸出中看到的內容:您的姓名和電子郵件地址,以及計算機對您進行提交的日期和時間的想法,以及為進行提交而保存的原因 ,即您的日志消息。 這些都是供您(或其他人)將來使用的:某天,也許明天,也許幾個月或幾年之后,您可以回顧一下您剛才所做的提交,並問自己: 我為什么要做那 ? 答案應該在您的日志消息中。
因為提交存儲文件(作為快照,時間凍結,不可變並且可以永久存在(或只要提交本身一直存在)),所以非常適合歸檔。 在將來的任何時候,您都可以回顧過去,並准確地查看當時保存的內容。 您無法更改:它是過去的,固定的,已凍結的時間。 稍后我們將看到,即使Git也無法更改它。
為了找到提交,Git需要一個名稱。 這些名稱不是分支名稱! 或者,更准確地說,您可以使用分支名稱開始,但這不是Git所需的名稱。 相反,任何提交的真實名稱是其哈希ID 。 每個提交的哈希值ID 似乎是隨機的,但實際上,它是上提交的全部內容的加密校驗,以在提交數據的每一個位極其敏感:所有凍結的快照,並您的姓名和時間-stamp和您的日志消息。 這就是為什么您或任何人都不能更改提交的原因:更改任何內容都會更改哈希ID,然后您將擁有一個新的不同的提交。 在進行新提交之前,沒人知道哈希ID是什么。 當時,它獲得了唯一的ID。 沒有人會將該ID用於其他任何提交! 沒有人可以改變什么提交:Git會知道,如果你嘗試,因為該ID不匹配了。 2
這個特殊的拼圖游戲有最后一兩個關鍵部分。 第一個是,在每個新提交中,Git都將前一次提交的哈希ID(真實名稱)存儲為該元數據的一部分。 也就是說,Git不會只是保存您的姓名和時間等,同時也節省了您的使用,使這個新提交的提交的原始哈希ID。 Git將此保存的哈希ID稱為提交的父級 。 這意味着每個提交都在向后看的鏈中指向其父提交。
例如,假設我們在存儲庫中只有兩個提交A
和B
A
是第一個提交,因此特意沒有父提交-這是特例。 但是B
是由A
制成A
,因此B
指向A
:
A <-B
如果您提取提交B
,執行一些工作,然后進行新的提交C
,則新的提交將自動指向B
:
A <-B <-C
這意味着Git只需要知道最后一次提交的表面上隨機的哈希ID。 在這種情況下,提交C
如果其實際的哈希ID是cba9876...
或其他值,Git可以使用它來查找C
的內容 。 這些內容包括提交B
的實際哈希ID。 然后,Git可以使用它來查找B
,其內容包括提交A
的實際哈希ID。 Git可以使用它來查找A
,而A
沒有父母,所以現在,Git終於可以停止向后工作。
從分支提示提交(例如,由分支名稱標識的C
向后工作的過程在Git中至關重要。 歷史就是這樣存在的 。 Git存儲庫中的歷史記錄是提交,這些提交通過這些向后的箭頭連接。 您從頭開始,一次走動一次,遍歷歷史,按照父箭頭查看可以到達的位置。
當分支名稱和其他此類名稱顯示出來時,這是最后一個拼圖碎片輸入圖片的地方。 讓我們暫停一下,在這里結束腳注,然后深入研究分支名稱和圖形繪制。
1 Git實際上是從索引制作快照的,但是我們不會在這里介紹這些細節,除了說要快照的內容(對於該提交,永遠凍結的時間)就是當時索引中的內容,這至少可能與您在工作樹中看到的內容有所不同。
2 Git實際上會在方便或適當的時候進行檢查。 這會自動檢測到Git存儲庫的意外損壞,例如在您嘗試將其存儲在Dropbox中時發生的情況。Dropbox有時會四處修改(和Git的)背后的文件,而Git會抓住它。 不幸的是,很少有修復損壞的存儲庫的好方法-而是,Git傾向於依賴Git存儲庫在各處復制的想法。 您可能在其他地方有一份不錯的副本,因此您完全可以將其扔掉。
任何現有的存儲庫(好吧,除了一個完全空的,新鮮的, 沒有提交的新存儲庫之外的任何其他存儲庫)都具有一組提交。 這些提交構成了我們剛剛看到的向后看的鏈,例如:
A <-B <-C
我們和Git需要某種方式來記錄該鏈中最后一次提交的哈希ID。
Git實現此目標的方法是Git稱為reference或refs 。 裁判的形式很多,但三巨頭是:
master
。 origin/master
。 (Git稱這些遠程跟蹤分支名稱或遠程跟蹤分支 ,我認為這是一個壞名字;我已改用遠程跟蹤名稱 ,我認為這很難弄錯。) v1.3
。 它們實際上都是由相同的基礎技術實現的,但在這里我們將它們視為單獨的名稱形式。 分支名稱具有特殊屬性; 所有其他名稱都缺少此屬性。
這些名稱之一的含義非常簡單:它只是Git對象的實際原始哈希ID,通常是提交。 3因此,像master
這樣的分支名稱指向分支中的最后一個提交-在此圖形中提交C
:
A--B--C <-- master
請注意,相互連接的箭頭從子對象中出來並指向(不可變的)父對象,這為我們提供了這種向后遍歷的方法。 我們不必費心將它們插入。但是, 分支名稱中的箭頭會更改 。
當我們向master
添加新的提交時,Git會自動更新名稱master
來保存新提交的哈希ID。 因此,如果我們現在創建一個新的提交,則新的提交D
將指向C
:
A--B--C <-- master
\
D
但是Git會立即調整master
使其不指向C
而是指向D
:
A--B--C--D <-- master
由於D
指向C
,我們仍然可以找到所有提交:我們從結尾開始,然后像往常一樣向后工作。 現在, C
是此過程中的第二個提交,而不是第一個。
3分支名稱必須包含提交對象哈希ID,而標記名稱則更靈活。 我們在這里不需要關心這一點。 因為遠程跟蹤名稱的值是從分支名稱中復制的,所以遠程跟蹤名稱也僅包含提交哈希ID。
Git是一個分布式版本控制系統。 這意味着每個Git存儲庫都是一種獨立的孤島,它需要的所有內容都在該存儲庫本地。 如果有許多提交多個分支機構,他們都在一個存儲庫:
A--B--C--D--G--H <-- master
\
E--F <-- dev
為了使Git真正有用,我們定期使用Git與其他Git用戶交換工作。 為此,我們交換了commits 。 由於這種密碼校驗和技巧,它們的哈希ID在所有地方的所有 Git中都是通用的。 給定快照和元數據, 每個地方的每個 Git都會計算相同的哈希ID 。 因此,如果我的存儲庫具有這樣的提交A
到H
(請記住,這些單個大寫字母代表着唯一的,大的丑陋哈希ID),並且我連接到您的存儲庫並且您具有提交H
,則您的存儲庫還必須具有與礦。
如果您沒有提交H
,那么我有您沒有提交。 如果你有一些犯I
還是J
, 你有一個承諾, 我不知道。 無論哪種方式,我們的Gits都可以交換哈希ID來查看誰擁有什么。 發送提交的人將發送它們,接收提交的人將接收它們,發送者將向接收者提供任何需要的新提交。
假設您正在接受我的新委托。 我有新的提交I
和J
,而我的新提交J
的名稱可以記住其哈希ID。 在我的存儲庫中,我有:
A--B--C--D--G--H <-- master
\
E
\
I--J <-- dev
無論出於什么原因,我都沒有像 dev
那樣提交F
相反,在(共享)提交E
之后,我對我的dev
進行了IJ
提交。
您的Git接受了我的承諾I
和J
我的承諾是I
有父母E
因此, 您的存儲庫現在具有以下內容:
A--B--C--D--G--H <-- master
\
E--F <-- dev
\
I--J <-- ???
您的 Git存儲庫將使用什么名字來記住我的提交I
? 最好不要使用dev
:如果您的Git使您的dev
指向commit I
,您將如何再次找到commit F
? 請記住,它具有一個顯然是隨機的哈希ID。 您將永遠無法猜測 。
因此,您的Git所做的就是使用遠程跟蹤名稱來記住我的分支。 您的Git會這樣做:
A--B--C--D--G--H <-- master, origin/master
\
E--F <-- dev
\
I--J <-- origin/dev
(假設我的master
指向H
)。
您存儲庫中的origin/master
和origin/dev
名稱是您的遠程跟蹤名稱 ,記住了master
和dev
。 4此外,假設您現在查詢Git,要求它在Git使用的普通向后走行方法中,比較dev
與origin/dev
可以到達的提交集。
從dev
開始,將要訪問的提交是F
,然后是E
,然后是D
,依次類推回到A
從origin/dev
,將要訪問的提交是J
,然后是I
,然后是E
,然后是D
,依次類推回到A
哪些提交是哪個步行特有的? 您從dev
到達的提交數量是您從origin/dev
不能到達的提交數量,反之亦然?
算出這些,然后與您的Git告訴您的內容進行比較:
# Your branch and 'origin/dev' have diverged, # and have 1 and 2 different commits each, respectively.
實際上,這里的拼圖游戲還缺少另一部分,當我們在下面談論git push
時,我們將在上一節中對其進行簡要介紹。
4 Git有時稱其為跟蹤,而不是記住 ,但這是Git嚴重濫用單詞的另一個地方。 我已經在遠程跟蹤中使用了它,但是至少在這里它是帶連字符的,並用這個詞作為形容詞修飾remote 。
git push
與git fetch
不同 上面的過程是您的Git從origin
的Git上找到的分支名稱創建遠程跟蹤名稱的過程,它特定於git fetch
。 當你有你的Git調出的Git在它發生origin
,把他們提交給你 。
當然,您可以讓您的Git在origin
調用他們的Git並發送提交。 這就是git push
操作,非常相似。 您的Git告訴他們的Git您所擁有的提交,而他們沒有。 讓我們畫一些。 我們將從此開始:
A--B--C--D--G--H <-- master, origin/master
\
E--F <-- dev
\
I--J <-- origin/dev
現在,我們將運行git checkout master
和git checkout -b newfeature/v4-json
或更簡單的命令:
git checkout -b newfeature/v4-json master
現在,我們有:
A--B--C--D--G--H <-- master, origin/master, newfeature/v4-json (HEAD)
\
E--F <-- dev
\
I--J <-- origin/dev
我們已經將特殊名稱HEAD
附加到newfeature/v4-json
以記住添加新提交時更新哪個分支名稱。
現在,我們將創建一個新提交。 它可能不止一個,甚至沒有一個 ,但我們只創建一個用於說明。 新的提交有一些大的丑陋的哈希ID,但我們在這里將其稱為K
:
K <-- newfeature/v4-json (HEAD)
/
A--B--C--D--G--H <-- master, origin/master
\
E--F <-- dev
\
I--J <-- origin/dev
現在,我們將使用以下命令讓您的Git在origin
調用Git:
git push -u origin newfeature/v4-json
您的Git撥號他們的Git並宣布您已提交K
和H
5他們沒有K
但是他們有H
所以他們讓您的Git通過其快照和元數據發送提交K
您的Git可以告訴您,由於它們具有H
因此它們也具有G
和D
及其之前的所有內容,因此您只需向他們發送K
及其內容。
然后,最后,您的Git詢問他們: 請,現在,如果可以,請設置名稱newfeature/v4-json
指向commit K
請注意,您沒有讓他們設置xpt/newfeature/v4-json
或類似的東西。 您讓他們設置了分支! 他們實際上還沒有newfeature/v4-json
,因此他們可以設置一個。 他們做到了! 現在, 他們的存儲庫中有一個newfeature/v4-json
,指向commit K
你的Git現在創建 遠程跟蹤名稱 origin/newfeature/v4-json
,指着承諾K
,記住他們的 newfeature/v4-json
,指向提交K
。 6但這僅表示您的圖形中有一個額外的名稱 ,如下所示:
K <-- newfeature/v4-json (HEAD), origin/newfeature/v4-json
/
A--B--C--D--G--H <-- master, origin/master
\
E--F <-- dev
\
I--J <-- origin/dev
由於使用-u
選項,您的Git也會立即運行:
git branch --set-upstream-to=origin/newfeature/v4-json newfeature/v4-json
這將為分支newfeature/v4-json
設置上游設置。 您的每個分支都可以具有一 (1)個上游設置,以這種方式使用它非常典型。 請參閱為什么我總是需要執行--set-upstream`嗎? 更多。
5您的Git 可以告訴他們有關F
,但前提是您在這里說過git push origin dev
。 使用帶有或不帶有-u
git push origin newfeature/v4-json
,您告訴Git:根據需要告訴他們有關K
, H
, G
, D
, C
, B
和/或A
提交。 您其他未共享的提交則有意保留為私有。
6請記住,由於哈希ID的魔力,提交K
在世界各地的每個 Git中都是通用的。 每個 Git通過其哈希ID都具有K
,然后就是該提交; 或者根本沒有K
,所以沒關系。
(這並不一定是100%的保證。假設的哈希ID K
實際上是b5101f929789889c2e536d915698f58d5c5c6b7a
,這是在Git倉庫的Git的本身提交的哈希值ID。如果你從來沒有你的 Git倉庫連接到一個Git倉庫GIT中,它是好的,您和他們具有相同的哈希ID的不同提交,但是如果您確實將Git存儲庫連接到Git的Git存儲庫,則會發生一些不太理想的事情。簡短的版本是您不會Git的提交,而他們卻沒有得到您的支持:這兩個倉庫現在根本無法合並,這對您和維護Git的人來說都完全可以,但另請參見新發現的SHA-1碰撞對您的影響git? )
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.