![](/img/trans.png)
[英]If I am a collaborator on someone's repository on Github, how do I get their repo onto my terminal?
[英]How do I push changes to someone else's repository (I'm a collaborator on), from a submodule of my own repository?
所以我有自己的存儲庫,我們稱之為“我的”,它包含一個子模塊存儲庫“他們的”。 我可以訪問他們的遠程存儲庫,因此我可以直接將更改推送到它。
我正在嘗試將我對“他們的”所做的更改推送回他們的遠程 GitHub 存儲庫,但我似乎無法讓它工作。 我可以將更改推送到我在 GitHub 上的遠程存儲庫“我的”,並且可以看到對“他們的”的新提交。 但是當我訪問他們的 GitHub 時,它沒有添加最新的提交。
子模塊不應該只是常規存儲庫,在另一個內部帶有一些額外的元數據嗎? 如果是這樣,為什么“他們的”目錄中的“git push”不起作用? 我試過從“他們的”內部提交和推送,然后從“cd ..”和“我的”內部提交/推送,但它也不起作用。
我已嘗試此處列出的步驟: Git submodule push無濟於事。 我只能假設,因為我正在嘗試推送到我不擁有的存儲庫,所以還需要做其他事情嗎?
~/Mine$ git remote -v
origin https://github.com/myUser/Mine.git (fetch)
origin https://github.com/myUser/Mine.git (push)
~/Mine/Their$ git remote -v
origin https://github.com/theirUser/Theirs.git (fetch)
origin https://github.com/theirUser/Theirs.git (push)
提交完成后,將其推送到分叉倉庫(即“我的”)。 從你的分支在正確的分支中打開一個拉取請求。 拉取請求獲得批准並合並后,您可以將更改從上游拉取到本地存儲庫。
然后更改將被添加到“他們的”存儲庫中。
你是對的:子模塊本身就是一個存儲庫。 這意味着您可以cd
或chdir
進入子模塊並以與使用任何其他 Git 存儲庫相同的方式開始使用它,包括運行git fetch
、 git checkout
、 git commit
等。
使子模塊成為子模塊的原因是,位於子模塊上方某處的其他 Git 正在控制子模塊,通常通過在其中運行git checkout hash-id
來控制子模塊。 這會將子模塊置於 Git 所謂的分離 HEAD模式。 (控制 Git 是超級項目。)
這種“分離頭”模式有點棘手。 您可以在這種模式下進行新的提交,但是當您這樣做時,大多數普通方法都無法找到它們。 它們暫時很容易通過特殊名稱HEAD
,但是這個特殊名稱HEAD
將被超級項目強行調整,它將chdir
進入子模塊並再次運行git checkout hash-id
,丟失1你所做的提交.
要將您在子模塊 Git 存儲庫中所做的提交發送到某個其他 Git 存儲庫,您必須在其他Git 存儲庫中為這些提交指定一個名稱。 通常,這意味着給他們一個分支名稱。 在您的存儲庫中使用分支名稱沒有硬性要求,因為您可以運行:
git push <remote-or-URL> HEAD:<name>
通過名稱HEAD
將子模塊存儲庫中標識的提交發送到另一個 Git,並禮貌地要求它創建或更新其名稱name
以指向該提交。 但是大多數人不喜歡使用/使用分離的 HEAD 模式。
一般來說,這意味着要在充當某些超級項目的子模塊的 Git 存儲庫中工作,您應該使用以下順序: 2
進入子模塊。 從這里到第 3 步,您只需將它用作常規 Git 存儲庫即可。
通過選擇分支名稱到git checkout
或創建指向當前提交的分支名稱來退出分離的 HEAD 模式。 需要注意的是,如果你選擇一些現有的分行名稱,這可能是一個不同於當前提交提交。 或者它可能與當前提交相同。
請記住,超級項目存儲庫早些時候告訴這個 Git:使用這個原始提交,通過它的哈希 ID進入分離的 HEAD 模式。 我們現在正在退出分離 HEAD 模式,這需要選擇或創建分支名稱。 如果你選擇一些現有的分支名稱,你就會被分支名稱選擇的任何提交所困擾。 但是,如果您正在子模塊存儲庫中開發新的提交,您可能需要一個分支名稱來記住它們。
現在,以通常的方式進行新的提交。 以通常的方式使用git push
。 提交將或不會以提交執行或不執行的通常方式進入接收存儲庫。 如果他們確實進入了接收存儲庫,則會以通常的方式創建或更新該存儲庫的分支名稱。
一切完成后,退出子模塊存儲庫,返回超級項目存儲庫。 現在是時候在superproject 中進行新的提交了。
我已經多次提到超級項目 Git 一直控制着子模塊 Git。 它在子模塊 Git 中執行chdir
並運行git checkout hash-id
。 這里的關鍵來自兩部分:
第一個問題的答案很復雜: git submodule update
做到了,但並非總是如此; 3 git checkout --recursive
這樣做(總是); 根據選項和設置,各種其他操作有時也可以做到。 也就是說,它不會發生,除非和直到你問這樣的事發生,但它並不總是很明顯,你問這樣的事發生。 我們要做的是確保在第二點再次發生之前解決第二點。
第二個問題的答案——超級項目 Git 從哪里獲得原始哈希ID——是它從超級項目中的提交中獲取它。 但是你已經在子模塊中進行了新的提交,並將其提交到上游到其他一些 Git 存儲庫,所以現在是時候在superproject 中進行新的提交,以記錄正確的哈希 ID,即新的哈希 ID提交您在子模塊中所做的。
與往常一樣,任何提交都不能更改; 和往常一樣,Git 從索引中的任何內容(又名staging area )進行新的提交。 當您提取一些現有提交時,Git 會將該提交中的文件讀取到索引/暫存區中。 如果存儲庫充當某個子模塊的超級項目,則此步驟還會從提交中讀取所需的哈希 ID (在該子模塊中)到索引中。 由於這不再是所需的哈希 ID,您現在的工作是將新的哈希 ID放入索引中。
在超級項目中執行此操作的命令是git add
。 與往常一樣, git add
將內容寫入索引。 對於普通文件,它將該文件的副本寫入索引。 4但是,對於子模塊,它:
HEAD
? ( git rev-parse HEAD
); 無論子模塊是否處於分離的HEAD
狀態,這都有效,因為git rev-parse HEAD
始終返回當前提交的原始哈希 ID。
因此,在git add path/to/submodule
,您選擇的(實際上是制作和推送的)提交的哈希 ID 現在記錄在超級項目的索引中。 您的下一次提交將記錄該原始哈希 ID。
假設其他一切都准備好了,您現在可以運行git commit
在超級項目中進行新的提交(這大概是,並且一直處於附加 HEAD 狀態,在某個分支名稱上)。 一旦你提交了這個新的超級項目,你就可以像往常一樣git push
了。
請注意此處步驟的仔細排序:
origin
存儲庫中的提交,在 suprerproject 中創建和推送一個提交,該提交引用子模塊提交的原始哈希 ID。 由於 Git 的分布式特性,可以在您的子模塊中進行提交但不將其推送到任何地方,然后在您的超級項目中進行提交並推送它。 任何獲得這個新提交的人都會得到一個提交,該提交通過原始哈希 ID 指向一個提交,他們不僅沒有,而且甚至無法獲得. 因此,第 3 步(“使提交對所有人可用”)必須在第 4 步中的push
之前發生。(第 4 步中的“進行提交”可以更早發生——注意不要推送它,並使用任何更新的內容重做提交哈希,如果子模塊提交出於任何原因必須重做。)
1失去這里的意思是“很難找到”。 提交本身不會立即消失:它們與其他丟失的提交具有相同的寬限期,您可以使用子模塊 Git 的HEAD
reflog 來查找它們,就像您在任何存儲庫中查找丟失的提交一樣——因為子模塊是畢竟只是另一個存儲庫。
2因為 Git 是一組工具,而不是預先打包的解決方案,所以還有很多其他方法可以實現您的目標。 這只是一種非常靈活的方式。
3特別是git submodule update
有很多更新方式。 使用一些參數,您可以直接git submodule update
來檢查git submodule update
的名稱,從而首先生成一個附加的 HEAD(而不是分離的 HEAD)! 這是腳注 2 所指內容的一部分。 git submodule update
的詳細工作非常復雜,所以我試圖在這個答案中避免這些變體。
4從技術上講,它用正確的文件內容寫出一個blob 對象——或者如果可能的話,不改變地重用一些現有的 blob 對象——然后將 blob 對象的哈希 ID 寫入索引,而不是實際的文件內容。 但是效果就像 Git 將文件復制到索引中一樣,只要你不深入到git ls-files --stage
和git update-index
的級別。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.