可以“就地”完成;尽管如此,我不能说你是否会认为这种方法是一种 hack,但它是我能想到的最直接的方法......
首先,听起来他的工作副本根本不是 git repo。在这种情况下,您可以在他的工作树上“就地”创建 git repo
git init
此时,他的工作副本将在这个新的 repo 中显示为未跟踪的文件。现在将 repo 与源关联并获取历史记录。
git remote add origin <origin-url>
git fetch
<origin-url> 与您用于克隆的网址相同。
此时,您仍然有一个“未出生”的master 分支,并且没有其他本地分支;您仍然拥有本地工作副本作为未跟踪的更改;并且您对遥控器上的所有内容都有远程跟踪参考。
接下来我要做的事情是
git add .
git diff origin/master
(我在这里假设如果本地版本是代码的修改副本,那么它是从origin/master 上的内容从修改的。如果不是,那么您至少需要知道“正确”的父提交将是,并替换对该提交的引用。我将继续假设 origin/master 现在,但如果这是错误的,请随时发表评论,我可以尝试相应地更新。)
在这里,我们填充索引并将其与远程版本进行比较,因为如果没有什么不同,那么你就完成了。只需擦除索引和工作树并检出master(这将创建本地master 并将其设置为跟踪origin/master)。
但听起来你不这么认为;所以如果你确实看到了差异,你需要创建一个新的提交。稍微棘手的部分是让git 了解这个新状态只是现有origin/master 提交的子状态。
有几种方法可以做到这一点,我相信对于哪种方法最好,意见会有所不同。一个简单的方法(但它确实使用了一些不太熟悉的命令)是
git merge $(git commit-tree -p origin/master -m "Commit Message" $(git write-tree))
...这可能需要一点解释。
首先这会根据索引创建一个新的TREE(项目内容的快照)。因为我们在做git diff之前做了一个git add .,所以索引反映的是本地版本。这会将新 TREE 对象的 ID 打印到标准输出。
我们将该 ID 传递给git commit-tree,它使用给定的父对象创建一个COMMIT 对象(我再次假设origin/master)、提交消息(在-m 之后填写适当的内容)和@987654342 @(我们刚刚从索引创建的那个)。这会将新 COMMIT 对象的 ID 打印到标准输出。
然后我们将新的COMMIT 对象合并到当前(未出生的)master 分支中,这有点奇怪,但就像快进到指定的COMMIT 一样。所以现在你有
x -- x -- O <--(origin/master)
\
L <--(master)
其中L 的内容等于本地副本;所以看起来就像您从 O 开始并进行了本地更改。此时您可以正常push。