3

我只是在学习 git,我有一个难题......

我不拥有两个项目:

  • 德丽拉
  • 胡里奥

背景

  • Delila 是在遥远的远古时代从 Julio 分叉出来的。
  • Julio 继续快速发展。
  • 我想将 Delila 中的一个功能放入 Julio。
  • 对于 Julio 的所有者来说,该功能没有任何意义,因为它不够通用(这就是为什么 Delila 的原作者从未费心提供拉取请求的原因)。
  • Delila 显然不想要 Julio 的所有新东西,因此提供从 Julio 到 Delila 的所有新东西的巨大拉取请求也是不明智的。

脑筋急转弯

现在,我想从 Delila 拿一个文件并将其放入 Julio,因为 Julio 包含了我需要的大量优点,而 Delila 包含了我真正可以使用的奇妙功能。

所以,务实地,我可以这样做:

  1. 将 Julio 分叉到我实际拥有的一个新项目(我将其称为 Benito)
  2. git clone Delila 获取旧代码
  3. git clone Benito 获取我的新代码的分支
  4. 将我需要的文件从包含Delila的目录复制到Benito
  5. 稍微调整一下,让它与周围的新东西一起工作,然后 git 将它添加到 Benito
  6. git commit Benito,git push it,去给自己泡一杯当之无愧的茶

除了茶的味道很酸。我把别人的工作归功于别人(如果你查看文件的历史,你只会看到我)并且我已经丢失了可能有用的历史信息(为什么哦为什么哦为什么那个疯狂的潜行者会这样做......?) .

那么在这种情况下正确的做法是什么?


更新

感谢@djechlin,我一直在玩这个,但我仍然无法让它工作。在这里,我通过在本地创建两个存储库 Julio 和 Delila 来模拟这种情况。所以,这是开始的情况:

胡里奥

~/playing/Julio (master)
$ git log
commit f72960c18392d843d40adfd1c7ab943162005879
Author: xxxxx
Date:   Tue Sep 24 08:46:50 2013 +0200

    A change after Delila left the building

commit eca80d52acefcb02baae48e717bd8c2d98685c5e
Author: xxxxx
Date:   Tue Sep 24 08:31:15 2013 +0200

    initial commit from Julio

德丽拉

~/playing/Delila (master)
$ git log
commit 0e7c530246bc782dbf30fb4ac425e031d3626bbe
Author: xxxxx
Date:   Tue Sep 24 08:39:06 2013 +0200

    Added changes for Delila

commit eca80d52acefcb02baae48e717bd8c2d98685c5e
Author: xxxxx
Date:   Tue Sep 24 08:31:15 2013 +0200

    initial commit from Julio

你可以看到 Delila 是从 Julio 分叉出来的,并且发生了一些变化。具体来说,为 Delila提交添加的更改是我想要维护的。

现在,根据答案,从 ~/playing 开始,我这样做:

 ~/playing
$ mkdir me

 ~/playing
$ cd me

 ~/playing/me
$ git clone ../Delila
Cloning into 'Delila'...
done.

 ~/playing/me
$ cd Delila

 ~/playing/me/Delila (master)
$ git remote rm origin

 ~/playing/me/Delila (master)
$ git filter-branch --subdirectory-filter someFolder -- --all
Rewrite 0e7c530246bc782dbf30fb4ac425e031d3626bbe (2/2)
Ref 'refs/heads/master' was rewritten

 ~/playing/me/Delila (master)
$ mkdir someFolder

 ~/playing/me/Delila (master)
$ mv * someFolder
mv: cannot move `someFolder' to `someFolder/someFolder'

现在,我想要整个文件夹,所以我这样做:

 ~/playing/me/Delila (master)
$ git rm theNewFeature
rm 'theNewFeature'

 ~/playing/me/Delila (master)
$ git rm anotherFileFromJulio
rm 'anotherFileFromJulio'

这是错误的做法吗?

回到答案:

 ~/playing/me/Delila (master)
$ git add .

 ~/playing/me/Delila (master)
$ git commit -m "filtered Delila"
[master b7fde89] filtered Delila
 2 files changed, 0 insertions(+), 0 deletions(-)
 rename anotherFileFromJulio => someFolder/anotherFileFromJulio (100%)
 rename theNewFeature => someFolder/theNewFeature (100%)

现在我想“分叉” Julio,所以我这样做:

 ~/playing/me
$ git clone ../Julio
Cloning into 'Julio'...
done.

 ~/playing/me
$ cd Julio

 ~/playing/me/Julio (master)
$ git remote rm origin

好的,回到答案的步骤......

 ~/playing/me/Julio (master)
$ git remote add repo-A-branch ../Delila

 ~/playing/me/Julio (master)
$ git pull repo-A-branch master
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 8 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (8/8), done.
From ../Delila
 * branch            master     -> FETCH_HEAD
Merge made by the 'recursive' strategy.
 someFolder/theNewFeature | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 someFolder/theNewFeature

 ~/playing/me/Julio (master)
$ git remote rm repo-A-branch

应该是这样的,那么让我们看看我们移植的特殊功能的日志......

 ~/playing/me/Julio/someFolder (master)
$ git log theNewFeature
commit b7fde8940d761f7babe13d8b6cdfa12fe1685390
Author: xxxxx
Date:   Tue Sep 24 09:01:43 2013 +0200

    filtered Delila

叹息 那我做错了什么?历史去哪儿了?

4

2 回答 2

2

这实际上完全在 git 的能力范围内。一般来说,这是你应该能够期望 git 做的事情。提交不仅仅是代码库快照,它们是(大致 - 合并创建分支)具有完整历史记录的代码库快照链接列表。Git 允许你重写历史,使它类似于你认为应该发生的事情。特别是,您不想破坏文件的历史记录,但也想导入它。

您的问题是您不想提取所有分叉的回购。所以只需使用filter-branch导入你需要的东西。这一次性完成了您需要的事情:保留这些文件,保留它们的历史记录,但销毁与这些文件无关的所有历史记录。

我希望自己能够做到这一点,您需要 1) 轻松使用filter-branch或 2) 将相关文件隔离在一个目录中。

这在这篇文章中有所描述

用于filter-branch销毁原始存储库中的所有内容,而不是您关心的目录中的所有内容。是的,你想先克隆和分离原始 repo 的副本。

git clone <git repository A url>
cd <git repository A directory>
git remote rm origin
git filter-branch --subdirectory-filter <directory 1> -- --all
mkdir <directory 1>
mv * <directory 1>
git add .
git commit

而且,简单地说,从只包含你关心的东西的新仓库中提取和合并。请记住,git repos 没有一些 ID 来说明它们是什么 repo。这是一个普通的操作——恰好有一个 repo B 的副本,它只包含新文件。

git clone <git repository B url>
cd <git repository B directory>
git remote add repo-A-branch <git repository A directory>
git pull repo-A-branch master
git remote rm repo-A-branch
于 2013-09-23T17:20:48.697 回答
0

好的,所以我想出了一种方法来达到我的预期。正如您从我的更新等中看到的那样,我认为过滤器后没有维护历史记录。实际上是这样,我只需要将 --follow 传递给参数...

除了有争议,请不要对我投反对票,这只是我作为尝试使用 git 完成工作并感到有些痛苦的人的看法:就我 个人而言,我觉得这在我不知道的存储库中并不是最佳的,我总是需要添加额外的 follow 参数来获取文件的完整历史记录(所以我现在将创建一个我使用的别名,而不是 just git log)。此外,github 在其漂亮的 Web UI 中默认不会这样做--follow,我怀疑这是很多人寻找历史的地方。

我意识到 github 等可以改进,但来自最终用户 - 我只想git mv让历史保持领先。之后,git mv我希望做git log并看到以前的一切。

但我只是一个用户,所以我知道什么。

无论如何,这就是我所做的,基于Git:从另一个存储库复制文件或目录,保留历史记录

git clone Delila
mkdir ~/mypatches
cd Delila/folderWithFile
export reposrc=fileToKeepHistory
git format-patch -o ~/mypatches $(git log $reposrc|grep ^commit|tail -1|awk '{print $2}')^..HEAD $reposrc

... Fork Julio ...

cd ~/
git clone JulioForked
cd Julio/folderWithFile    
git am ~/mypatches/*.patch

...Make my changes...

git commit -m "my changes"
git push origin master

它奏效了!现在我在github中查看我想要维护其历史的讨厌的文件,它的所有奇妙荣耀都在那里!

呸。

于 2013-10-07T08:05:38.097 回答