【问题标题】:Git mark a file as older before mergeGit 在合并之前将文件标记为旧文件
【发布时间】:2017-02-17 20:57:49
【问题描述】:

所以我做了一个 git pull 来克隆 2/1/17 的最新 repo

我从 2015 年 3 月 6 日的一个 repo 中获得了 file.txt,我对其进行了更改,但我没有 repo 的副本。

我需要合并最新的 repo 对 file.txt 所做的更改。

我想用旧的 file.txt 复制最新的 repo 的 file.txt,但 git 认为我从 2/1/17 file.txt 中删除了一堆东西。

如何让 git 知道 3/6/15 的 file.txt 实际上是 2/1/17 存储库中的 file.txt 的旧版本并将它们合并?

编辑:

这是一个插图

REPO1 - 日期为 2/1/17 {包含 file1.txt,最后更新时间为 2/1/17}

DIRECTORY DIR1 {包含 file1.txt,最初来自 2015 年 3 月 6 日,但后来对其进行了更改。最后一次更改是 2/6/17}

来自 REPO1 的 file1.txt 需要与来自 DIRECTORY DIR1 的 file1.txt 合并。

我该怎么做?

【问题讨论】:

  • 不清楚你的工作流程是什么,或者你是如何尝试合并这些更改的——你是在 PR'ing 它们,你是在尝试将它们合并到一个特性分支中,你是在尝试生成一个补丁 - 你正在尝试做什么,你一直在做什么,以及它到底是如何失败的?
  • 在问题得到改善之前投反对票。
  • Git 不关心也不存储文件日期。 (提交有一个时间戳,但实际上它们有 两个 时间戳,两者都不是文件日期。)合并时,Git 只关心合并基础的 和两个提示提交。
  • 忘记日期;只考虑内容。这些更改被删除,或者更准确地说,文件的内容恢复到与之前相同的方式。至于 Git 关心(根本不关心),那是因为旧方法更好,所以它也是新方法。如果您想要返回另一种旧方式,并且在提交中,只需从提交中提取另一种旧方式。现在又是新的方式了。 (然后,如果您的提交尚未发布(推送),您甚至可以将多个 oops-not-that-way-this-way 提交折叠为单个 this-is-the-right-方式提交。)
  • 好的,让我尝试一个直接的问题。存在或曾经是您确实想要的文件版本。 该文件是否存储在提交中? 还是仅在工作目录中,现在完全删除了? (我问的主要原因是提交不会覆盖任何东西。每个提交都是永久性的:这就是提交的全部意义。此外,提交不存储更改,他们存储快照。因此你在这里说的东西没有意义。)

标签: git version-control merge


【解决方案1】:

在 Git 中,日期并不重要。提交是真正重要的事情——更准确地说,是提交及其关系(不是日期,而是提交父/子关系)。

这里有一些措辞问题,因为“克隆”和“拉取”是具有精确(或半精确)含义的技术 Git 术语。让我们按照出现的顺序来看看:

所以我做了一个 git pull 来克隆最新的 repo ...

这没有意义。您可以克隆一个存储库:

git clone <url>

买一个新的;或者您可以进入您已有的存储库,并要求它更新内容:

cd existing-repo
git ...     # many use pull here, but that's a mistake, in my opinion

猜猜#1

对于这一部分,我猜你的意思是你运行了git clone 并创建了一个新的存储库,它是给定&lt;url&gt; 的某个上游存储库的克隆。我们称这个全新的副本 R(用于存储库)。它有一堆提交,都是从上游克隆的。它没有你自己的提交。

我从 2015 年 3 月 6 日的 repo 获得了 file.txt,我对其进行了更改,但我没有 repo 的副本。

所以,除了这个新克隆的存储库 R 之外,您在任何地方都没有提交。您只是在 R 之外的某个地方保存了一个文件。 (运气好的话,你仍然有这个文件的干净保存版本。)

我需要合并最新的 repo 对 file.txt 所做的更改。

现在您遇到了一个中等规模的问题,因为您不知道您原来的file.txt 来自哪个提交。 Git 存储库存储提交,它们是完整的快照,而不是变更集。自从您从某个提交中复制 R 后,您无法轻松找到他们进行了哪些提交,因为您没有该原始提交的 ID。

(您可以将您保存的file.txt 与他们最新的file.txt 进行比较,这可能是一种方法。)

如何让 git 知道 3/6/15 的 file.txt 实际上是 2/1/17 存储库中的 file.txt 的旧版本并将它们合并?

你没有。日期根本不重要;合并需要每个文件的三个版本:

  • 基础版本,您和他们开始使用的版本;
  • 您当前的版本(日期无关,只是“您的最新版本”);和
  • 他们当前的版本(日期再次无关)。

Git 或任何三向合并系统此时可以做的就是进行两个比较:

  • 改变了什么?也就是我们如何修改基础文件来生成你的文件?
  • 他们改变了什么?也就是说,我们如何修改基础文件以拿出他们的文件?

然后系统可以组合这些更改。

但你刚才说你只有一个 file.txt。大概,那是你最新的。您需要两个版本:基本版本和最新版本。

如果您确实拥有这两个版本,则可以回避 Git 所做的大部分工作,而只需使用文件级合并(Git 将其作为一种辅助程序包含在内):

git merge-file --diff3 my-latest-file.txt base-file.txt their-file.txt

(这都可以在任何存储库之外完成)。这可能存在合并冲突——您更改了某些内容的地方,他们更改了某些内容,并且合并算法无法确定要保留两个不同更改中的哪一个。在这种情况下,文件以冲突标记包围的两个更改(以及--diff3 和基本文本)结束,因此当您编辑文件时,您可以找到冲突,并决定如何解决它们。

猜猜#2

也许您确实有两个保存的file.txt 版本:您从它们那里获得的原始基本版本(在您随后删除的克隆中)和您当前的版本。在这种情况下,您也许可以更直接地使用 Git。您需要做的是在您为自己创建的新分支上进行包含您的版本文件的提交

困难的部分是您需要将这个新分支从原始file.txt 位于该存储库中的位置分离出来。这意味着您必须找到包含原始 file.txt 的提交的 ID。

有一些面向脚本的方法可以找到此类提交(在这里您可以实际上使用 Git 保存的时间戳来加快搜索此类提交的速度)。因为提交存储快照,所以可能有 许多 个提交以这种形式包含此文件,具体取决于它随时间变化的程度。如果您知道要使用哪个 Git 哈希 ID,或者知道可以解析为正确 Git 哈希 ID 的标签名称,那将是最好和最简单的。但如果没有,请参阅Which commit has this blob?

cd R                      # enter the repository you cloned
git checkout <hash>       # get detached HEAD on the correct commit
... check to make sure file.txt is the right one ...
git checkout -b personal-branch

这最后一步创建了一个新分支,以便您可以将file.txt您的 版本复制到适当的位置并提交:

cp /path/to/my/version/of/file.txt file.txt
git add file.txt          # tell Git to save this one
git commit -m 'update as of 2/6/17' # or use a better commit message

现在您有了自己的分支,拥有自己的提交,所以现在您可以让 Git 将您的工作与他们的工作合并:

git checkout master
... make sure file.txt is theirs ...
git checkout personal-branch
... make sure file.txt is yours ...
git merge master    # get every change they made and merge with ours

这可能存在合并冲突(与您使用 git merge-file 看到的相同),您必须像以前一样解决这些冲突。如果是这样,您必须运行 git commit 来保存合并结果。如果没有,git merge 会为您运行 git commit。无论哪种方式,您现在都可以为新提交输入提交消息。

猜猜#3

在这里,我假设您确实运行了git pull。所有git pull 都运行git fetch,然后是git merge。这里的问题是您只能在现有存储库中运行git pull,然后您说您没有。要使用git pull,您必须拥有一个。

如果您有一个,它在git merge 之前有哪些提交?您可以从这些提交中获得此 file.txt 的哪些版本?也许其中一个 提交具有易于识别的基本版本,这将允许您自己进行三向合并,或者像猜测 #2 那样进行新的提交,并让 Git 进行三-为你合并。

【讨论】:

    【解决方案2】:

    如果目录 dir1 中的 file.txt(3/6/15) 是相同 repo 和分支的旧版本,则不需要合并更改,因为历史记录已经包含更改。如果你需要你的工作目录显示file.txt的3/6/15版本,你只需要使用git checkout &lt;the commit id contains the version 3/6/15 of file.txt&gt;

    如果您想在当前版本中添加 file.txt(3/6/15) 的内容,可以使用以下命令合并文件(假设您当前的分支是 master):

    git checkout -b temp
    

    将目录 dir1 中的 file.txt 复制到本地 repo 工作目录中

    git add .
    git commit 
    git checkout master
    git cherry-pick <commit id you just add in temp branch>
    

    file.txt会有冲突,修改保存file.txt

    git add .
    git cherry-pick --continue
    

    现在将目录 dir1 中的 file.txt 合并到 repo1 中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-11
      • 1970-01-01
      • 2016-01-31
      • 1970-01-01
      • 2019-07-22
      • 2014-01-28
      • 1970-01-01
      相关资源
      最近更新 更多