如何使用git/github管理两个独立但非常相似的代码库?

8

什么是在git和github中处理两个不同但非常相似代码库的最佳方法?

背景

我有一个用于小型shell脚本项目的git存储库。它只有2或3个代码文件,我通常只在单个文件中工作。虽然我最初创建这个项目是为了满足我的特定目标,但我写它以使其对他人更普遍有用。我编写通用用例版本,然后修改它以适用于我的特定目标。在特定版本中,我可能会修改变量、放入密码、交换一些代码的顺序、去掉for循环等等。

我尝试过的方法

我尝试了两种不同的方法,但都没有像我认为的那样优化:

  1. 两个单独的代码库
    • 问题:在一个代码库中修改的代码不能轻松且有选择性地合并到另一个代码库中。
  2. 一个代码库中的两个分支
    • 问题:这些分支最终需要合并。我并不想完全将它们合并在一起,而是有选择性地合并部分代码。
    • 问题:当尝试在分支之间使用合并命令时,很容易混淆合并哪个分支的哪些代码。我不知何故在它们两个之间合并了完全意外的代码,并且没有任何指示表明错误的合并,直到我查看了两个分支文件的内容。

我还看到了关于 SVN 的 如何将两个单独但相似的代码库合并为一个 SVN 代码库? ,但这对我来说难以理解,因为我不了解 SVN。我认为这是一个不同的问题,因为他并不打算公开此代码的一个版本。

我希望解决的用例

具体问题出现在以下情况下:

  • 评论同步 - 我正在准备我的专门版本,并注意到我可以在一行的末尾添加一个解释性注释。我添加了它,但是这个注释现在不在通用版本中。
  • 我不想分享的东西 - 我正在准备我的专门版本,我添加了密码或更改了操作顺序。我不希望这些更改传递到通用版本。
  • 同一文件 - 上述两个更改通常会在同一个文件中,这使得将它们合并在一起变得困难。有交互式合并,但我不知道交互是否可以在单个文件中完成。
  • 通用 -> 专用 - 我或其他人可能会更新通用版本,以具有对于专用版本也有用的新内容或注释。我想从通用 -> 专用将它们带过来,而不会影响专用版本中的任何其他代码差异。

Git与Github的区别

大多数情况下,我的问题是想知道如何在Git的限制范围内完成这个操作。然而,这可能会影响与GitHub的交互方式。我已经将一般版本上传到了GitHub上。但是,专业版不应该上传到GitHub上。我认为,如果我很小心地使用了上面的分支方法,就不会同时推送两个分支......但我始终不确定。无论如何,解决方案应该允许有一个公共版本和一个仅保留本地的版本......即使它有点复杂或需要小心处理。
4个回答

6

这可以很容易地通过两个分支完成。我不确定为什么你说“在一个代码中进行修改后,不能轻松且有选择性地合并到另一个分支中”,因为在Git中合并是非常容易的。

我建议的结构是,有一个用于您的通用版本和一个用于您的个人版本的分支。合并应该只朝一个方向发生,从通用分支到个人分支。这意味着您对通用版本所做的任何更改都会被合并到个人版本中。

换句话说,这是可以接受的......

git checkout personal
git merge general

你永远不应该做的事情是...

git checkout general
git merge personal

如果您在个人版本中进行了更改,并决定将相同的代码添加到通用版本中,那么您应该可以通过挑选来轻松处理此问题。只需要事先考虑好如何组织个人分支中的提交。您需要在个人分支中有一个仅包含要移植到通用版本中的更改的提交,然后只需从个人分支上挑选它并放置到通用分支上即可。
两个存储库可以完成同样的事情。这将降低意外上传您的个人版本到Github的风险,但使用两个不同版本将会更加繁琐。
个人建议是在同一个存储库中使用两个分支。

+1,因为双分支方法轻便简单。我在我的回答中也推荐了它。 - Eric O. Lebigot
好的,现在试一下...看起来工作正常,除了我需要学习如何处理合并冲突。我执行了 git merge personal 命令,出现了3个冲突。我希望有一个交互式的过程,让我决定哪些行应该被合并。使用 git merge -i personal 命令可以实现这个功能吗? - Nay
这个方法可行并被标记为被接受的答案。下面其他回答中的信息也很有帮助。我不得不在http://progit.org/book/ch3-1.html上阅读了解分支和合并的管道。这很有帮助,但Git真的很复杂。我接下来要做的是找到一个直观而有用的合并工具。Emerge太难用了,opendiff也不容易理解。 - Nay

1

我赞同使用两个分支的想法:一个公共分支用于一般版本(推送到GitHub),另一个私有分支用于你的专业代码(不在GitHub上发布)。然而,我想补充说git stash是一个必不可少的工具,它可以让你在你所描述的情况下做你想做的事情(你正在处理个人版本,但你发现需要在通用版本中进行更改)。

实际上,将通用更改始终实施在通用分支中,然后执行

git checkout personal
git merge general

现在,除此之外你还可以有用地使用git stash; 让我们来看一个场景,假设你正在更新专业版本并考虑一般性的更改:

  1. 将当前更改保存到专用版本中:

    git stash
    

    这会将与上次提交相比的更改存储起来,而不会创建新的提交。这对于存储未提交的正在进行中的工作非常有用。

  2. 您转到一般分支以进行您考虑的一般更改:

    git checkout general  # 或者 master,或者您的一般分支的任何名称
    

    然后,您可以像往常一样实现您的一般修改并提交它。

  3. 在继续专用版本的工作之前,您导入了一般更改:

    git checkout personal
    git merge general
    

    git 足够智能,可以很好地完成此操作:只需将最新的、通常有用的更新应用于您的代码即可。

  4. 通过导入您存储的正在进行中的工作,您可以恢复在专用分支上的工作:

    git stash pop
    

就这样了!关键是要使用 git stash 来保存你的更改,而不必为此创建提交,然后使用 git stash pop 将更改应用回来。


感谢您提供的存储内容。我更倾向于在“个人”分支中进行更改。例如,我刚刚更改了一个需要在“个人”分支上定制的变量定义。在这样做的过程中,我注意到该变量的注释可能会更好。我继续更新它,就在“个人”分支中。现在,在保存该文件后,如果有一些命令可以说“好的,现在去交互式地将其合并回“通用”的分支中,在这个交互中,我要选择只将评论带到“通用”中”。我认为这就是所谓的挑选樱桃的意思。 - Nay
1
@NickYeates: git cherry-pick 只允许你有选择地导入一些 提交。这意味着你可以这样使用它:将特殊更改提交到个人分支;将一般更改提交到个人分支;挑选最后一个提交并将其应用于一般分支。git stash 更加灵活,因为它允许你避免提交;如果你希望你提交的代码始终处于工作状态,这可能很有用。总之,cherry-pickstash 都很有用;如果你都知道,你可以真正做出最方便的选择。 - Eric O. Lebigot

1
为了避免将您的专业版本推送到github,请将push.default配置设置为tracking(或对于git >= 1.7.4.2,设置为upstream)。有关详细信息,请参见http://longair.net/blog/2011/02/27/an-asymmetry-between-git-pull-and-git-push/
无论您是使用单独的存储库还是仅使用分支,合并都应该同样有效。总体而言,您最终需要真正擅长合并。其中很多内容将来自于深入了解git在分支、合并和变基方面的底层工作方式。与其他一些版本控制系统不同,我发现git需要深入了解其内部才能真正正确地使用它。

哇,那真是一個難以理解且冗長的頁面。我不明白這個設置會做什麼,所以我現在打算跳過它,小心操作。 - Nay
1
是的,那个涉及到了太多细节。请查看https://dev59.com/mnNA5IYBdhLWcg3wdtv5的前两个答案,希望能有一个更简单的解释。 - Russell Davis

0

使用 git 子模块。如果您想保留子模块的单独分支,请在该项目的存储库中创建一个分支,并将所有更改保留在该分支的本地副本中,并仅在子模块检出中使用该分支。

不同变更集之间的合并是您需要半手动完成的事情。Git具有出色的合并支持,如果您不将两个分支相距太远,应该能够通过最少的手动干预来完成。Github(或任何其他托管提供商)与此无关。如果您想保留分支私有,请不要将其推送到公共存储库。就这么简单。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接