git:如何添加和提交更改到一个远程分支而不是另一个远程分支?

时间:2016-04-27 07:06:01

标签: git github version-control

所以我知道推送到特定遥控器的方法是:

git push <remote branch> master其中master是我的本地分支

我在本地做了一些敏感的更改,我想推送到远程A而不是远程B.但是要推送到远程A,我需要在我可以推送之前在我的本地分支上添加和提交我的更改。但是,在我这样做之后,不会在我的本地分支历史记录中提交?我是否必须在将来推送到远程B之前手动删除该提交,或者是否有更成熟的方法来执行此操作? (因为每次我在远程A上工作时我都要记得再次进行更改,反之亦然B)

2 个答案:

答案 0 :(得分:0)

其中一些取决于你想给Git多少信任,因为在过去的糟糕时期(git 1.5或1.6左右),我看到Git将对象发送到它不应该发送的遥控器。所以我,至少,这不会是这种信任 - 但这就是假设的工作方式。

我们需要一些定义,否则我们会被Git中一些不太好的命名所绊倒。它们位于下方(接近末尾),以便您在熟悉它们时可以跳过它们。

最重要的是,当您执行push时,您的git将向远程发送您的分支提示提交以及从该点可以访问的所有提交(即,所有它的祖先)直到遥控器已有的任何提交。它还将包括这些提交所需的所有文件。它 只发送 那些提交和文件,即,如果某些敏感文件或数据在这些提交中,并且遥控器没有已经,远程应该在推送后没有它。

最终,这可能意味着您应该为两个遥控器保留两组不同的分支。或者 - 更好 - 首先不要将任何敏感数据放入Git。将其保存在存储库之外的某个位置。如果需要可能包含此类数据的配置文件,请在存储库中包含无敏感数据的示例配置,并使用.gitignore 避免将真实配置放入存储库。

讨论

请记住,分支名称&#34;指向&#34;特定提交(通过包含其ID):

$ git rev-parse master
3ad15fd5e17bbb73fb1161ff4e9c3ed254d5b243

并且提交指向它们的父提交(通过包含它们的ID),以及指向blob的树,它们可以获取与这些提交一起使用的文件。要使用提交,Git需要一些起点,例如SHA-1哈希3ad15fd...。它将在所有这些指针之后从那里向后工作,以便检查任何特定的提交。每个ID(提交,树或文件)都为Git提供了真正的名称&#34;底层对象,Git使用这个真实名称来提取实际内容。

因此,如果某个文件中存在敏感数据,Git存储它的方式是在某个blob ID下。通过Git看到它的方法是使用提交的ID启动Git,Git使用它来查找树和blob ID。然后,Git使用树指定的名称提取blob对象,以便您现在拥有一个具有正确名称和敏感数据内容的文件。

如果Git根本没有blob对象,那么很明显,你无法从Git中获取它。如果它有blob对象,但没有提交点(通过树),你不能通过文件名获取 - 但你可以,通过一些维护命令,让Git向你显示每个blob&#39 ; s原始ID并通过ID提取所有ID,从而找到该数据。 (通常它比那更容易,只有git fsck --lost-found。)

这意味着为了确保敏感数据不在某些Git存储库中,您必须确保blob本身不存在。这也意味着任何引用blob的提交都不能存在,因为Git不会允许你提交一个缺少&#34;#34;斑点。 (这样的存储库被认为是破坏的:尝试使用它时会出错,尽管Git会尽力让你恢复任何数据。)

git push语法和语义

git push的语法简化为我们关注的内容:

git push remote refspec

当你运行它时,git首先根据 remote 设置连接到指定的 url (实际上,它的 pushurl 如果设置,则返回 url (如果没有)。远程(通常是某些远程主机,例如github)运行一个命令,通常为git receive-pack,然后从您自己的git push读取请求。

您的git push首先发送提交对象的ID,主要是将这些对象提供给远程运行的receive-pack。遥控器回复了&#34;我已经有了&#34;或者&#34;好的,我会接受它,发送给我。&#34; Git的工作只是提供完成推送所需的那些对象。您的Git 首先提供通过解析您提供的refspec的 src 部分找到的提交ID,然后提供完成该提交所需的树和blob ,以及那个提交的祖先,直到遥控器说的那些点#34;我已经有了#34;。这就是你的Git知道发送什么的方式,并且只能发送遥控器上尚未发送的内容。 1

然后你的Git打包这些对象并发送包。此应该仅包含 提供和接受的对象。这些可以进一步压缩你的Git知道他们的Git所拥有的对象,因为它声称它已经拥有它们。

(在过去的糟糕时期,事情似乎无法正常工作,因为我的发送机器会向遥控器发送不必要的,实际上无法访问的对象。这不是假设的发生。我不确定在提议/接受阶段或包装构建阶段是否失败,或者是否是由我当时正在做的其他相当不正统的事情引起的。)

最后,你的Git向他们的Git发送了一个相当于&#34;的请求,现在请将您的参考 ref 设置为特定的哈希&#34;,其中 {{ 1}} 是refspec的 ref 部分的名称,哈希是Git通过解析 dst <找到的ID / em> refspec的一部分。他们的Git可以决定允许这个,或者根据他们设置的规则拒绝请求。 (当且仅当它是快进或新的分支创建时,默认规则是允许它用于分支。我还在这里对删除进行了修饰。)

将短名称​​ src 名称转换为全名参考有一点魔力:git会检查您的 dst 查看它是分支还是标记,并根据需要将 src 扩展为dstrefs/heads/。如果您提供全名 refs/tags/ ,您的Git会跳过此步骤。如果你完全省略refspec的dst部分,你的Git会根据一些相当复杂的规则为它们的Git构造完整的分支或标记名称。对于分支,通常结果与您自己的分支的名称相同。

换句话说,如果你这样做:

:dst

然后你的Git将通过互联网电话(假设一个远程URL)调用git push remote1 mybranch:theirbranch 的Git,打包他们所需要的所有对象(提交,树和文件/ blob)还没有他们需要的remote1,并要求他们让他们的分支mybranch指向该提交。

如果你这样做:

theirbranch

你的Git会在git push remote2 differentbranch:theirbranch 上调用Git并将其发送给你所需的任何对象以与remote2匹配,并要求他们将其分支differentbranch设置为指向theirbranch命名的ID。

在这种特殊情况下(此哈希来自git本身的存储库),你也可以这样做:

differentbranch

请注意,这一次,您已指定了原始提交ID,因此您必须拼出远程分支的全名。和以前一样,这将调用远程控制器,与它进行通信以查看它是否已经有git push remote3 3ad15fd:refs/heads/branch ,如果需要也可以发送它,还要发送任何需要的祖先提交,树和blob。最后,它会发送请求让他们的Git将3ad15fd5e17bbb73fb1161ff4e9c3ed254d5b243设置为branch。如果他们接受,他们现在拥有该提交及其所有祖先(包括每个合并提交和祖先),以及所有提交的所有树和blob。

1 这会跳过一个重要的优化:遥控器实际上是通过列出SHA-1和它已有的引用开始的,这让你的Git甚至都不会提供这些优化。

定义:远程

远程只是一个名称,如3ad15fd5e17bbb73fb1161ff4e9c3ed254d5b243origin,您可以在其下存储本地存储库配置中的各种条目。您必须设置的(通常最初是通过克隆隐式)是upstream,通常为urlgit://...http://...形式。 Git也存储了其他几个配置条目,包括一个或多个ssh://...条目。使用fetch =在您的编辑器中查看您的配置(注意不要修改它),或者只需运行git config --edit或类似内容进行查看,您会看到以下内容:

less .git/config

同样,远程只是名称,在本例中为[remote "origin"] url = git://some.host.somewhere.com/path/to/repo.git fetch = +refs/heads/*:refs/remotes/origin/*

定义:分支

&#34;分支&#34;在Git is ambiguous。我在这里使用的含义是可移动指针,更具体地说是分支名称,例如originmaster。这个名字有一个&#34;全名&#34;变体,所以如果你创建一个名为develop的(常规的,本地的)分支 - 这是一个坏主意,但 偶然发生 - 你可以命名origin / Bruce(分支)与origin / Bruce(远程跟踪分支具有相同的名称,但具有不同的完整名称)不同。如果您在前面写origin/Bruce,即refs/heads/,或者在命名不佳的布鲁斯分支refs/heads/master的情况下,则会得到全名。

Git在显示您的分支名称时往往会剥离refs/heads/origin/Bruce部分,因为通常不需要它。 (对于像refs/heads/这样不幸命名的分支可能很重要,但Git仍然会删除前缀。)

定义:远程跟踪分支

远程跟踪分支只是一个名称,其全名表单以origin/Bruce开头,然后包含远程名称。因此,refs/remotes/是远程refs/remotes/origin/master上的分支master的远程跟踪分支,而origin是分支refs/remotes/origin/Bruce的远程跟踪分支。当向你展示这些名字时,Git往往会剥离Bruce

定义:hash(SHA-1)和object(commit,tree,blob,annotated-tag)

Git hash 是像refs/remotes/这样丑陋的SHA-1字符串之一。这些是git内部保留的实体的真实名称。每个提交都有一个唯一的哈希;实际上,每个唯一对象都有一个唯一的哈希值。

Git中的对象是一个内部存储项,其名称是Git的哈希之一。有四种对象;这里最有趣的两个是&#34;提交&#34; (哪些商店提交)和&#34; blob&#34; (存储文件内容)。另外两个是&#34; tree&#34;对象(为ID映射生成名称,以便git可以告诉您,例如,名称为3ad15fd5e17bbb73fb1161ff4e9c3ed254d5b243的blob应该可以在名称9a31f...下访问)和带注释的标记对象(存储带注释的标签,通常指向提交)。

定义:参考

Git中的引用只是用于分支和标记的通用全名表单,还有其他一些内容。我们在这里关心的主要是分支机构。您通常可以使用短名称 - 使用myfile.txt等管道命令时会出现异常,或者当您有两个git update-ref s等不幸名称时会出现例外情况,而Git会为您找出全名。

定义:refspec

Git refspec 只是一对由冒号origin/Bruce分隔的引用,带有可选的前导加号。左侧的引用是 : (源)引用,右侧的引用是 src (目标)。在某些情况下,但不是所有情况下,您可以省略 dst src。当省略:dst部分时,如果没有前导:dst,它看起来就像一个引用名称,你只需要知道它实际上是一个refspec。

定义:祖先

一个提交是另一个提交的 ancestor ,如果通过跟随所有各种父ID指针,我们可以从第二次提交返回到第一次提交。出于Git的目的,提交也是其本身的祖先。因此,commit是它自己的父它自己的子节点,而它的父节点只是它的父节点。祖父母是祖先;孩子或孙子不是。

答案 1 :(得分:0)

1&GT;我想如果你改变你的分支然后做一个提交,它将被推送到那个特定的分支本身:

  

git checkout A
  git commit -m&#34; message&#34;
  git push origin A:refs / for / A

2 - ;如果你已经完成提交,你可以先恢复它,然后更改分支,然后提交并推送:

  

git reset --soft HEAD~
  git checkout A
  git commit -m&#34; message&#34;
  git push origin A:refs / for / A