简体   繁体   English

如何将更改从我自己的存储库的子模块推送到其他人的存储库(我是合作者)?

[英]How do I push changes to someone else's repository (I'm a collaborator on), from a submodule of my own repository?

So I have my own repository, let's call it "mine", which contains a submodule repository "theirs".所以我有自己的存储库,我们称之为“我的”,它包含一个子模块存储库“他们的”。 I have access to their remote repository, so I can push changes to it directly.我可以访问他们的远程存储库,因此我可以直接将更改推送到它。

I'm trying to push the changes I've made to "theirs" back to their remote GitHub repository but I can't seem to get it to work.我正在尝试将我对“他们的”所做的更改推送回他们的远程 GitHub 存储库,但我似乎无法让它工作。 I can push the changes to my remote repository "mine" on GitHub, and there the new commits to "theirs" are visible.我可以将更改推送到我在 GitHub 上的远程存储库“我的”,并且可以看到对“他们的”的新提交。 But when I visit their GitHub it hasn't added the latest commits.但是当我访问他们的 GitHub 时,它没有添加最新的提交。

Aren't submodules supposed to just be regular repositories, inside another with some extra metadata?子模块不应该只是常规存储库,在另一个内部带有一些额外的元数据吗? If so, why does "git push" from within the directory "theirs" not work?如果是这样,为什么“他们的”目录中的“git push”不起作用? I've tried committing and pushing from within "theirs" and then "cd .." and commit/push from within "mine" but it doesn't work either.我试过从“他们的”内部提交和推送,然后从“cd ..”和“我的”内部提交/推送,但它也不起作用。

I have tried the steps listed here: Git submodule push to no avail.我已尝试此处列出的步骤: Git submodule push无济于事。 I can only assume that because I'm trying to push to a repository that I don't own, something else needs to be done?我只能假设,因为我正在尝试推送到我不拥有的存储库,所以还需要做其他事情吗?

~/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) 

Once the commits are done push it forked repo (ie "mine").提交完成后,将其推送到分叉仓库(即“我的”)。 From your fork open a pull request in the correct branch.从你的分支在正确的分支中打开一个拉取请求。 Once the pull request is approved and merged you can pull the changes from upstream to your local repo.拉取请求获得批准并合并后,您可以将更改从上游拉取到本地存储库。

Then the changes will get added to "theirs" repository.然后更改将被添加到“他们的”存储库中。

You are correct: A submodule is a repository in its own right.你是对的:子模块本身就是一个存储库。 This means you can cd or chdir into the submodule and start using it the same way you would use any other Git repository, including running git fetch , git checkout , git commit , and so on.这意味着您可以cdchdir进入子模块并以与使用任何其他 Git 存储库相同的方式开始使用它,包括运行git fetchgit checkoutgit commit等。

What makes a submodule a submodule is the fact that some other Git, positioned somewhere above the submodule, is controlling the submodule, normally by running git checkout hash-id in it.使子模块成为子模块的原因是,位于子模块上方某处的其他 Git 正在控制子模块,通常通过在其中运行git checkout hash-id控制子模块。 This puts the submodule into what Git calls detached HEAD mode.这会将子模块置于 Git 所谓的分离 HEAD模式。 (The controlling Git is the superproject .) (控制 Git 是超级项目。)

This "detached HEAD" mode is a bit tricky.这种“分离头”模式有点棘手。 You can make new commits in this mode, but when you do, they're not findable by most ordinary means.可以在这种模式下进行新的提交,但是当您这样做时,大多数普通方法都无法找到它们。 They're easily findable for the moment by the special name HEAD , but this special name HEAD will be forcibly adjusted by the superproject, which will chdir into the submodule and run git checkout hash-id again, losing 1 the commits you've made.它们暂时很容易通过特殊名称HEAD ,但是这个特殊名称HEAD将被超级项目强行调整,它将chdir进入子模块并再次运行git checkout hash-id ,丢失1你所做的提交.

To send, to some other Git repository, commits you've made in your submodule Git repository, you must give those commits a name in the other Git repository.要将您在子模块 Git 存储库中所做的提交发送到某个其他 Git 存储库,您必须其他Git 存储库中为这些提交指定一个名称 Usually, that means giving them a branch name over there.通常,这意味着给他们一个分支名称。 There's no hard requirement to use a branch name in your repository, as you can run:您的存储库中使用分支名称没有硬性要求,因为您可以运行:

git push <remote-or-URL> HEAD:<name>

to send the commit identified in your submodule repository via the name HEAD , to the other Git, and politely ask it to create or update its name name to point to that commit.通过名称HEAD将子模块存储库中标识的提交发送到另一个 Git,并礼貌地要求它创建或更新其名称name以指向该提交。 But most people don't like working on/with detached HEAD mode.但是大多数人不喜欢使用/使用分离的 HEAD 模式。

What this means, in general, is that to do work in the Git repository that is acting as a submodule for some superproject, you should use the following sequence: 2一般来说,这意味着要在充当某些超级项目的子模块的 Git 存储库中工作,您应该使用以下顺序: 2

  1. Enter the submodule.进入子模块。 From here through step 3, you'll just work with this as a regular Git repository.从这里到第 3 步,您只需将它用作常规 Git 存储库即可。

  2. Exit detached HEAD mode by selecting a branch name to git checkout , or by creating a branch name pointing to the current commit.通过选择分支名称git checkout或创建指向当前提交的分支名称退出分离的 HEAD 模式 Note that if you choose some existing branch name, that may be a different commit from the current commit.需要注意的是,如果你选择一些现有的分行名称,这可能是一个不同于当前提交提交。 Or it may be the same commit as the current commit.或者它可能与当前提交相同

    Remember, the superproject repository earlier told this Git: use this raw commit, by its hash ID to get into detached HEAD mode.请记住,超级项目存储库早些时候告诉这个 Git:使用这个原始提交,通过它的哈希 ID进入分离的 HEAD 模式。 We're now getting out of detached HEAD mode, which requires picking or creating a branch name.我们现在正在退出分离 HEAD 模式,这需要选择或创建分支名称。 If you pick some existing branch name, you're stuck with whatever commit that branch name chooses.如果你选择一些现有的分支名称,你就会被分支名称选择的任何提交所困扰。 But if you're developing new commits in the submodule repository, you probably want a branch name to remember them.但是,如果您正在子模块存储库中开发新的提交,您可能需要一个分支名称来记住它们。

  3. Now, make new commit(s) in the usual way.现在,以通常的方式进行新的提交。 Use git push in the usual way.以通常的方式使用git push The commits will, or won't, go to the receiving repository in the usual way that commits do or don't.提交将或不会以提交执行或不执行的通常方式进入接收存储库。 If they do make it to the receiving repository, that repository's branch name will be created or updated in the usual way.如果他们确实进入了接收存储库,则会以通常的方式创建或更新该存储库的分支名称

  4. Once everything is done, exit the submodule repository, returning to the superproject repository.一切完成后,退出子模块存储库,返回超级项目存储库。 It's now time to make a new commit in the superproject .现在是时候在superproject 中进行新的提交了。

I already mentioned, several times, that the superproject Git keeps controlling the submodule Git.我已经多次提到超级项目 Git 一直控制着子模块 Git。 It does a chdir into the submodule Git and runs git checkout hash-id .它在子模块 Git 中执行chdir并运行git checkout hash-id The key here comes in two parts:这里的关键来自两部分:

  • When does the superproject Git do this to the submodule?超级项目 Git 什么时候对子模块做这个?
  • Where does the superproject Git get the raw hash ID?超级项目 Git哪里获取原始哈希 ID?

The answer to the first question is complicated: git submodule update does it, but not always;第一个问题的答案很复杂: git submodule update做到了,但并非总是如此; 3 git checkout --recursive does it (always); 3 git checkout --recursive这样做(总是); various other operations can sometimes do it, depending on options and settings.根据选项和设置,各种其他操作有时也可以做到。 That is, it doesn't happen unless and until you ask for it to happen, but it's not always obvious that you are asking for it to happen.也就是说,它不会发生,除非和直到你问这样的事发生,但它并不总是很明显,问这样的事发生。 What we're about to do is to make sure we address the second point, before it happens again.我们要做的是确保在第二点再次发生之前解决第二点。

The answer to the second question— where does the superproject Git get the raw hash ID —is that it gets it from commits in the superproject .第二个问题的答案——超级项目 Git 从哪里获得原始哈希ID——是它从超级项目中的提交中获取它。 But you've made a new commit in the submodule, and delivered it upstream to some other Git repository, so now it's time to make a new commit in the superproject , to record the right hash ID, ie, the hash ID of the new commit you made in the submodule.但是你已经在子模块中进行了新的提交,并将其提交到上游到其他一些 Git 存储库,所以现在是时候在superproject 中进行新的提交,以记录正确的哈希 ID,即新的哈希 ID提交您在子模块中所做的。

As always, no commit can ever be changed;与往常一样,任何提交都不能更改; and as always, Git makes new commits from whatever is in the index (aka staging area ).和往常一样,Git 从索引中的任何内容(又名staging area )进行新的提交。 When you extract some existing commit, Git reads the files from that commit into the index / staging-area.当您提取一些现有提交时,Git 会将该提交中的文件读取到索引/暂存区中。 If the repository is acting as a superproject for some submodule, this step also reads the desired hash ID (in that submodule) from the commit, into the index.如果存储库充当某个子模块的超级项目,则此步骤还会从提交中读取所需的哈希 ID (在该子模块中)到索引中。 Since that's no longer the desired hash ID, your job is now to put the new hash ID into the index.由于这不再是所需的哈希 ID,您现在的工作是将新的哈希 ID放入索引中。

The command that does this, in the superproject, is git add .在超级项目中执行此操作的命令是git add As always, git add writes stuff into the index.与往常一样, git add将内容写入索引。 For a normal file, it writes into the index a copy of that file.对于普通文件,它将该文件的副本写入索引。 4 For a submodule, though, it: 4但是,对于子模块,它:

  • enters the submodule for a moment;进入子模块片刻;
  • asks that Git: what is the raw hash ID for the commit identified by your HEAD ?Git:什么是原始哈希ID为提交你确定HEAD ( git rev-parse HEAD ); ( git rev-parse HEAD );
  • stuffs the resulting hash ID, whatever it is, into the superproject Git's index, in the slot for that submodule.将生成的哈希 ID(无论它是什么)填充到超级项目 Git 的索引中,在该子模块的插槽中。

This works whether the submodule is in detached HEAD state or not, because git rev-parse HEAD always returns the raw hash ID of the current commit.无论子模块是否处于分离的HEAD状态,这都有效,因为git rev-parse HEAD始终返回当前提交的原始哈希 ID。

So, after git add path/to/submodule , the hash ID of the commit that you selected (and in fact made and pushed) is now recorded in the index in the superproject.因此,在git add path/to/submodule选择的(实际上是制作和推送的)提交的哈希 ID 现在记录在超级项目的索引中。 Your next commit will record that raw hash ID.您的下一次提交将记录原始哈希 ID。

Assuming everything else is also ready, you can now run git commit to make a new commit in the superproject (which presumably is, and has been all along, in attached-HEAD state, on some branch name).假设其他一切都准备好了,您现在可以运行git commit在超级项目中进行新的提交(这大概是,并且一直处于附加 HEAD 状态,在某个分支名称上)。 Once you do make this new superproject commit, you're ready to git push it as usual.一旦你提交了这个新的超级项目,你就可以像往常一样git push了。

Note the careful ordering of steps here:请注意此处步骤的仔细排序:

  1. Enter the submodule.进入子模块。
  2. Make the commit(s) in the submodule, on branches for simplicity, but however you make them is OK.为简单起见,在子模块中的分支上进行提交,但是无论您如何进行提交都可以。
  3. Send those commits to wherever it is that people clone the submodule from, so that that Git has them.发送这些提交到哪里它是人们从克隆子模块,使Git有他们。 This step requires setting a branch or tag name in that other Git.此步骤需要在其他 Git 中设置分支或标签名称。
  4. Now that other people can access that commit in the submodule's origin repository , make and push a commit in the suprerproject that refers to the submodule commit's raw hash ID.现在其他人可以访问子模块的origin存储库中的提交,在 suprerproject 中创建和推送一个提交,该提交引用子模块提交的原始哈希 ID。

It is possible—because of Git's distributed nature—to make the commit in your submodule but not push it anywhere, then to make the commit in your superproject and push it.由于 Git 的分布式特性,可以在您的子模块中进行提交但将其推送到任何地方,然后在您的超级项目中进行提交推送它。 Anyone who gets this new commit gets a commit that refers, by raw hash ID, to a commit they not only don't have, but can't even get .任何获得这个新提交的人都会得到一个提交,该提交通过原始哈希 ID 指向一个提交,他们不仅没有,而且甚至无法获得. So step 3 ("make the commit available to everyone") must happen before the push in step 4. (The "make commit" in step 4 can happen earlier—just be careful not to push it, and to redo it with any updated commit hash, if the submodule commit has to be redone for any reason.)因此,第 3 步(“使提交对所有人可用”)必须在第 4 步中的push之前发生。(第 4 步中的“进行提交”可以更早发生——注意不要推送它,并使用任何更新的内容重做提交哈希,如果子模块提交出于任何原因必须重做。)


1 Losing here means "make hard to find". 1失去这里的意思是“很难找到”。 The commits themselves won't vanish right away: they have the same grace period that other lost commits get, and you can use the submodule Git's HEAD reflog to find them, the same way you find lost commits in any repository—because the submodule is just another repository, after all.提交本身不会立即消失:它们与其他丢失的提交具有相同的宽限期,您可以使用子模块 Git 的HEAD reflog 来查找它们,就像您在任何存储库中查找丢失的提交一样——因为子模块毕竟只是另一个存储库。

2 Because Git is a set of tools, not a pre-packaged solution, there are a lot of other ways to accomplish your goal. 2因为 Git 是一组工具,而不是预先打包的解决方案,所以还有很多其他方法可以实现您的目标。 This is just one very flexible way.这只是一种非常灵活的方式。

3 In particular, git submodule update has many update modes . 3特别是git submodule update有很多更新方式 With some arguments, you can direct git submodule update to check out a name in the submodule, resulting in an attached HEAD (not a detached one) in the first place!使用一些参数,您可以直接git submodule update来检查git submodule update名称,从而首先生成一个附加的 HEAD(而不是分离的 HEAD)! That's part of what footnote 2 is referring to.这是脚注 2 所指内容的一部分。 The detailed workings of git submodule update are quite complicated, so I'm trying to avoid these variants in this answer. git submodule update的详细工作非常复杂,所以我试图在这个答案中避免这些变体。

4 Technically, it writes out a blob object with the right file contents—or reuses some existing blob object unchanged, if possible—and then writes the blob object's hash ID into the index, rather than the actual file content. 4从技术上讲,它用正确的文件内容写出一个blob 对象——或者如果可能的话,不改变地重用一些现有的 blob 对象——然后将 blob 对象的哈希 ID 写入索引,而不是实际的文件内容。 But the effect is as if Git copied the file into the index, as long as you don't get down to the level of git ls-files --stage and git update-index .但是效果就像 Git 将文件复制到索引中一样,只要你不深入到git ls-files --stagegit update-index的级别。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如果我是 Github 上某人存储库的合作者,我如何将他们的存储库放到我的终端上? - If I am a collaborator on someone's repository on Github, how do I get their repo onto my terminal? 如何在GitHub上提交并推送到其他人的存储库? - How can I commit and push to someone else's repository on GitHub? 我是其他人建立的私人仓库的合作者,如何在我的个人资料中公开它? - I'm a collaborator on a private repo that someone else set up, how do I make it public on my profile? 如何与其他人同时对存储库进行更改? - How do I make changes to the repository at the same time as someone else? 如何从别人那里分叉我自己的存储库副本? - How to fork my own copy of repository from someone else? 如何从github存储库中删除子模块? - How do I remove a submodule from my github repository? 我是从另一个人的存储库中克隆出来的,现在如何将代码从本地计算机推送到自己的存储库中? - I've cloned from another person's repository, now how do I push the code from my local computer to my own repository? 如何推送我从 github 克隆的存储库并对我的 github 存储库进行更改? - How do I push the repository I cloned from github and made changes to it to my github repo? 如何进入与我正在提取的存储库不同的存储库 - How to push into a repository different from the repository I'm pulling from 如何在共享存储库中提取其他协作者创建的分支? - How do I pull a branch created by another collaborator in a shared repository?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM