我的用例有点奇怪。我是以编程方式执行此操作,无法访问重置软/混合,并合并。
我的本地机器上有一个回购。我在本地进行了一些文件更改,但没有提交。有权访问同一个仓库的其他人也进行了更改并将其推送到远程。我希望我的本地目录的文件内容成为远程的头部。我基本上想要强制推送,但保持遥控器上的现有历史记录。一个例子应该有希望澄清:
Repo A:
file1.txt
file2.txt
Commits:
"Init repo"
我和人2克隆回购A.人2进行一些更改并推动它们。远程仓库现在看起来像这样:
Repo A:
file1.txt
file3.txt
Commits:
"add file3"
"rm file2"
"Init repo"
在我当地的回购中,我做了一些工作。现在我的本地仓库看起来像这样:
Repo A:
file1.txt
file2.txt
fileA.txt
Commits:
"Init repo"
我想做一个提交并推送,以便遥控器看起来像这样:
Repo A:
file1.txt
file2.txt
fileA.txt
Commits:
"did my own thing"
"add file3"
"rm file2"
"Init repo"
我刚刚进行了一次新的提交,其中文件内容与我的本地目录完全匹配。我不想合并或类似的东西。但重要的是保持了历史。
这可能吗?我相信它可以通过软复位来完成,但我无法访问它。另一种选择是将repo A克隆到另一个文件夹,删除内容并复制我的本地文件。但这会太慢了。还有其他办法吗?
答案 0 :(得分:2)
请做。它应该工作。我正常使用它并且它会变色。
git pull --rebase
答案 1 :(得分:1)
你要求做一件奇怪的事情,而且可能应该使用rebase(我看你已经接受了这个答案)。但是使用rebase不会做你要求的奇怪的事情。
如上所述,无法执行此操作。此外,您提供的描述具有误导性,因为存储库不包含文件;存储库包含提交。然后提交代表完整文件的树,但在你告诉Git提取一些特定的提交之前,你只需要进行一系列的提交。
如果您可以放松自己的限制,可以做到。我将在下面描述如何以及为什么。
当你有两个或更多的存储库时,就像这里的情况一样,每个存储库都有自己的提交集合,它自己的分支名称如master
,它自己的概念是"提示最末端" (最近,如果你愿意)提交每个分支名称。在这种特殊情况下,涉及三个独立的存储库:
origin
的那个,你打电话给#34; repo A"; 通过使用git clone
让您的计算机在origin
上调用另一个Git并将整个存储库(所有提交)复制到您自己的位置,您完成了最后一项操作。您的Git使用了他们的分支名称,例如master
,并将其重命名为远程跟踪名称,如origin/master
。最后,您的git clone
运行git checkout master
,让您的Git创建您的拥有主服务器并将其设置为指向通过哈希ID提交:他们列出的相同哈希ID他们的master
,您现在正在呼叫origin/master
。
此git checkout
也填写了索引和工作树。索引是你让Git构建下一个提交的地方 - 这就是为什么在Git中你总是需要运行git add
。您的工作树是您实际看到文件的地方。它们与您自己的Git存储库相关联,但实际上并不是的存储库 - 与索引不同,它占据了一种阴影的位置,在提交的中间(永久性和不可更改)和工作树(这是你工作的地方,因此实际上改变了事情)。
当然,第2个人执行相同的git clone
,它会创建存储库的副本,然后他们的git checkout
创建他们的master
并填写他们的 index和work-tree。
现在,任何存储库中的提交都有很多有趣的东西。一个是这个"(大多数)永久性的和(完全)不可改变的#34;属性。另一个是每个提交存储与该提交一起使用的所有文件的快照 - 当您git checkout
特定提交时,这就是获取这些文件的原因。
一个关键的,相当神奇的属性是每个提交都有一个保证唯一的哈希ID ,如7668cbc60578f99a4c048f8f8f38787930b8147b
。当我说 unique 时,我的意思是 unique:无论存储库有多少个副本,7668cbc60578f99a4c048f8f8f38787930b8147b
都是相同的提交每个副本。它是存在还是不存在,取决于您是否已经拾取并保存它(如果其他人制作它),或者自己制作(如果您打算制作它)。
最后一个关键项是每个提交都可以存储先前或父提交的哈希ID。它是这些哈希ID,加上像master
这样的分支名称存储了最新的,它产生了历史记录。 Git总是从最近的提交开始,通过在master
之类的分支名称下找到的哈希ID,然后使用它。然后,如果你想回顾历史,Git会找到提交的父ID,并查看父提交中的文件。父母有另一个父母 - 当前提交的祖父母 - 还有另一组文件;等等。
每当有人在任何Git中进行 new 提交时,Git所做的就是将当前提交保存为父ID,并构造一个新的,唯一的(全部)世界各地)新提交的哈希ID:
... <-hash <-hash <-tip <-- master
变为:
... <-hash <-hash <-old-tip <-new-tip <-- master
由于散列ID在任何地方都是唯一的,任何Git都可以判断它是否已经有其他Git提交的提交:如果它是相同的提交,则ID匹配
当你将你的Git连接到另一个Git时,你让Git向他们询问他们最新的分支机构等等。他们告诉你他们的master
现在是一些新的哈希。然后你的Git可以让他们的Git发送该提交,如果有必要,可以发送它的父级,以及祖父母等等,直到你有相同的提交。现在,您拥有 plus 所有新历史记录的所有历史记录,而无需获取所有旧历史记录;现在你Git更新你的origin/master
以记住他们的新分支提示。
或者,您可以将Git 发送新提交到他们的Git。但是当你这样做时,你的Git会要求他们的Git将他们的 master
设置为相同的哈希作为你自己的master
。因此,要实现这一点,您必须先获取所有新提交,然后添加您自己的新提交,以便他们能够完成提交。
以上是您通常会运行git fetch origin && git merge origin/master
或git fetch origin && git rebase origin/master
的原因。但这不是您想要做的,因为它不会占用您当前的工作树并使您的新提交的整个内容
你想完全忽略Person 2在工作方面所做的事情,而保留 Person 2在提交历史方面做了什么。
这是一件非常奇怪的事情,但这就是你想说的。
要获取该提交历史记录,您必须 git fetch
上游提交。如果我们将提交哈希标记为单个字母(而不是实际的哈希ID),那么这就是你得到的:
...--E--F--G <-- master (HEAD)
\
H <-- origin/master
现在使用您的工作树构建一个新提交,但是在第2个人的最新提交之上构建它,您需要git reset --soft
。这使您可以移动当前分支名称,master
,使其指向与他们origin/master
相同的提交。在git reset --soft origin/master
之后,您的存储库内容 - 这不会考虑您的索引和工作树 - 如下所示:
...--E--F--G
\
H <-- master (HEAD), origin/master
由于--soft
,您的索引和工作树未更改。您现在可以git add -A
或类似地从工作树和git commit
更新索引。这将生成一个新的提交I
,其父级为H
:
...--E--F--G I <-- master (HEAD)
\ /
H <-- origin/master
并且其内容完全忽略了 Person 2做了什么来提交H
,这是你要求的奇怪的事情。