所以我知道推送到特定遥控器的方法是:
git push <remote branch> master
其中master是我的本地分支
我在本地做了一些敏感的更改,我想推送到远程A而不是远程B.但是要推送到远程A,我需要在我可以推送之前在我的本地分支上添加和提交我的更改。但是,在我这样做之后,不会在我的本地分支历史记录中提交?我是否必须在将来推送到远程B之前手动删除该提交,或者是否有更成熟的方法来执行此操作? (因为每次我在远程A上工作时我都要记得再次进行更改,反之亦然B)
答案 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
扩展为dst
或refs/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甚至都不会提供这些优化。
远程只是一个名称,如3ad15fd5e17bbb73fb1161ff4e9c3ed254d5b243
或origin
,您可以在其下存储本地存储库配置中的各种条目。您必须设置的(通常最初是通过克隆隐式)是upstream
,通常为url
,git://...
或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。我在这里使用的含义是可移动指针,更具体地说是分支名称,例如origin
或master
。这个名字有一个&#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
。
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会为您找出全名。
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