Git推送到远程而不拉,并防止删除远程文件

时间:2019-03-26 15:25:45

标签: git push pull

我在不同的节点上有几个本地Git存储库。它们都将自己的文件推送到同一远程上的同一分支,并且这些文件从一个节点到另一个节点完全不同。无需节点即可访问其他节点的文件。为了节省带宽,我不想在节点推送文件之前在节点上进行total.Hoursgit pull有什么方法可以将文件从节点推送到远程服务器上的单个分支,而又不会删除其他节点提交的文件?

1 个答案:

答案 0 :(得分:1)

TL; DR

为每个节点分配一个私有名称,该专有名称保留给该节点。我将在下面举例说明如何与人类演员一起使用。您必须为机器角色想出自己的系统。然后,您必须想出自己的系统来使用使用生成的提交-这并不像选择一个提交那样简单;您将需要一个真正的部署引擎。

简短的回答是“否”和“是”,或者是mu。这里的基本问题是git push不会推送文件; git push发送 commits 。这些提交由其唯一的哈希ID标识。例如,如果要向您发送提交a123456,我可以运行:

git push <string-that-leads-my-Git-to-your-Git> a123456:<some-name>

请记住,每个提交都列出了自己的父提交哈希ID,这很快就变得很重要。此a123456必须具有一些父项-一些其他哈希ID。但是,现在让我们来看一下这个特定的git push命令。

当我选择运行此git push命令时,必须在此git push命令中放在冒号左侧的内容是 commit哈希ID的说明符我要发送给您的提交。 (在这种情况下,我选择了一个刚刚组成的缩写哈希ID。)在该命令中,我必须放在冒号右侧的是 name 想要让您的Git用来保存此提交。

我们待会儿再讲这个;现在,我们需要研究Git提交的工作方式。

提交如何工作

Git的真正工作方式非常简单。每个提交都有自己唯一的哈希ID。您已看到这些哈希ID,因为git log显示了它们。但是它们又大又丑,没人能记住它们。这就是为什么让Git为我们记住它们的原因。除了最后一个(分支的最新提交或 tip 提交)以外的所有哈希值 都被记住一些其他提交中。

例如,我们可能从一个只有三个提交的小型存储库开始:

A <-B <-C

我们可以使用单个大写字母来绘制Git的工作方式,而不必写出它们实际的,显然是随机的哈希ID。提交C latest 提交,因此它内部具有提交B的实际哈希ID(无论是什么)。因此,我们说提交C 指向提交B

同时,提交B包含提交A的实际哈希ID:B指向AA是一个特例:这是第一次提交;因为我们进行A时没有先前的提交,所以它不能指向先前的提交。因此A指向无处,这使Git停止了。

分支名称如何工作

尽管如此,我们必须找到提交C。 Git只能(至少直接)通过其哈希ID来查找。因此,我们必须将提交C的哈希ID保存在某个地方。我们可以把它写下来在纸片或白板上,然后输入,但这很糟糕。取而代之的是,Git让我们将哈希ID存储在名称中。

您可以在此处使用的名称有多种形式,但是我们最常使用的名称是分支名称。分支名称具有一个特殊的属性:我们可以使用git checkout branch在该分支上获取。完成后,Git会将特殊名称HEAD 附加到该分支名称。分支名称本身仅包含实际提交的原始哈希ID(在这种情况下为提交C),因此分支名称​​指向提交,就像每个提交都指向其父级一样:< / p>

A <-B <-C   <-- master (HEAD)

现在,我们要创建一个新分支dev。我们将创建它,指向提交C-一个提交有两个名称;没关系,这只意味着所有三个提交现在都在两个分支上。我们还将让Git将HEAD附加到dev

A--B--C   <-- dev (HEAD), master

现在,我们将进行一次 new 提交。由于我们已检出C,因此新提交的 parent 将为C。 Git将使用我们决定快照的任何源代码(必须使用git add复制到Git的 index 中)来创建新提交,并使用任何元数据已经告诉Git使用它,以及它自己发现的所有信息(我们的姓名,电子邮件地址,日志消息,当前时间以及提交C的哈希ID):

A--B--C
       \
        D

请注意D如何通过元数据中的父提交哈希ID指向C

所有数据和元数据都进入加密哈希算法,以便写出提交D的行为会为 生成新的哈希ID。新的提交D。现在迈出了神奇的一步:Git使用新的哈希ID来简单地覆盖分支名称(附有HEAD的分支名称),以便当前分支名称指向新的提交:

A--B--C   <-- master
       \
        D   <-- dev (HEAD)

其他名称未更改。现在,当前分支名称dev指向新提交,因此dev记住哈希DHEAD也没有更改-它仍附加到dev

git push的工作方式

当我的Git呼叫您的Git时,我已经告诉我的Git:

  • 我要发送的提交,
  • 我想让我的Git叫什么名字来记住你的提交。

我的Git问您的Git:嘿,您有提交a123456吗?(假设a123456是我的提交D,这是简单的四次提交上面的存储库。)由于我只是制作它,所以您没有它。因此,我的Git会问你的Git是否有C,因为我的Git必须发送所有导致导致 D的提交,而不仅仅是发送D本身。您确实有C,或者没有。如果您不这样做,我的Git也会询问B,依此类推。但是您可能已经有C您的 master可能指向共享提交C

因此,我的Git仅打包提交D并发送。然后,我的Git要求您的Git设置您的分支名称之一

如果我选择让您的Git设置您的dev,而您没有拥有一个dev,那么您的Git将会创建您的dev,现在具有与我相同的功能。

同时,假设Ernie在Ernie的Git中具有相同的A-B-C提交,但是Ernie进行了新的dev和新的提交E。厄尼现在拥有:

A--B--C   <-- master
       \
        E   <-- dev

Ernie没有D,因为Ernie的Git尚未与我的Git对话,反之亦然。在我将D发送给您并要求您创建您的 dev之后,Ernie已 his Git向您发送了 his < / em> E,并要求您将dev设置为指向提交E

您的Git现在具有:

        E   <-- polite request to set your `dev` here
       /
A--B--C   <-- master
       \
        D   <-- dev

如果,您的Git服从了礼貌的请求,则Git会将您的dev指向E,因此忘记了如何找到{{1} } 。所以您的Git只是说不,我不能那样做。

如果Ernie将他的D更改为使用git push,Ernie将他的礼貌请求更改为命令:设置--force指向dev,我的意思是!您的Git仍然可以拒绝该命令,但是默认情况下,您的git将服从该命令,并丢失E。这就是您尝试使用此技术时看到的。

请注意,不管我如何运行D,我的Git都会要求您的Git设置一些名称。上面显示的方法(我在冒号的左侧选择一个哈希ID,在右侧选择一个名称)不是我们通常拼写git push的方式。我们通常写:

git push

但是 的意思是git push origin dev 。左侧的内容git push origin dev:dev是我的提交dev的名字。右边的内容D就是实际名称dev。 Git只是让我们表达了这一点,而中间没有冒号。

问题是名字冲突,所以请避免名字冲突

无论发送提交到您的中央收集点的方式如何选择分支,您都需要在 中央发生什么收集点很简单。在上面,我们有两个参与者:有我,以dev的名义发送我的承诺dev,有一个厄尼,以D的名义发送他的承诺{{1} }。之所以失败,是因为我的dev和他的E都回到了共享的D,但是我们试图使用 one 名称来记住两个不兼容的提交。

但是,如果您给我一个私人名称,该怎么办?为简单起见,假设我叫Dave(不是),并且您让我将E推到C而不是dev。我会跑:

incoming/dave

与此同时,您将运行Ernie:

dev

现在在您的 Git存储库中,您将拥有以下内容:

git push origin dev:incoming/dave

假设现在我进行一次新的提交git push origin dev:incoming/ernie ,而Ernie进行一次新的提交 E <-- incoming/ernie / A--B--C <-- master \ D <-- incoming/dave ,我们每个人都在F上工作。记住,提交哈希ID是通用的,因此我的G和Ernie的dev定义为不同的丑陋哈希ID。 Ernie将与父母F一起推G。他将通过他的名称G来找到自己的Git E,但要求您设置您的名称G。您将得到以下结果:

dev

您的incoming/ernie可以安全地进行更新,因为 E--G <-- incoming/ernie / A--B--C <-- master \ D <-- incoming/dave 会按照需要返回到incoming/ernie

我还没有发送我的G,但是当我发送时,这个E将指向F,我将为您更新F。这样就可以了,因为D会指向incoming/dave并指向incoming/dave:不会丢失任何提交。

很显然,某人-您-您-必须做一些事来集成这些独立的开发线。但这不是Dave和Ernie的问题,那是你的问题。