[英]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.这意味着您可以
cd
或chdir
进入子模块并以与使用任何其他 Git 存储库相同的方式开始使用它,包括运行git fetch
、 git checkout
、 git 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
Enter the submodule.进入子模块。 From here through step 3, you'll just work with this as a regular Git repository.
从这里到第 3 步,您只需将它用作常规 Git 存储库即可。
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.
但是,如果您正在子模块存储库中开发新的提交,您可能需要一个分支名称来记住它们。
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.
如果他们确实进入了接收存储库,则会以通常的方式创建或更新该存储库的分支名称。
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:这里的关键来自两部分:
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但是,对于子模块,它:
HEAD
?HEAD
? ( git rev-parse HEAD
); git rev-parse HEAD
); 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:请注意此处步骤的仔细排序:
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 --stage
和git update-index
的级别。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.