“分层” git 存储库
我每天都使用 git 一段时间了,这次我遇到了一个问题,我可以这样描述。
我有一个存储库,其中包含整个网站结构,并且网络根位于存储库的根目录中。一切都很好,直到它成为单个站点的存储库。然而,同一个存储库现在用于多个站点 - 基本上是相同的站点,使用不同的语言,小的模板调整,不同的图形等。这些东西自然是版本化的。
有一个主分支,它保存站点的原始源代码,我希望主分支(或其他一些分支)保存在所有站点上通用的代码,因为最终会出现过于站点的更改 -具体包含在回购协议的通用部分中。
接下来,每个使用此源代码的站点都有一个分支。所有这些分支(例如,site1、site2 和 site3)都是从 master 分支创建的,每个站点都会克隆正确的分支。
嗯,这似乎是个好主意,直到我开始在各处进行更改。
如果我在 site1 分支上进行了更改,并且需要将该更改复制到 site2 分支,我会选择从一个分支到另一个分支的提交。合并是不可能的,因为 site1 分支上还有其他不属于 site2 分支的更改。针对这种情况是否有其他更优雅的解决方案,或者挑选樱桃正是为了这个目的?
现在,对我来说真正的“问题”是当我更改主控时,然后我想将所有这些更改复制到所有分支。当然,考虑到所有分支都是 master 的后代,并且我确实希望在所有 site* 分支中进行这些更改,我切换到每个分支并合并 master。
这为所有分支创建了一个看起来相当令人讨厌的历史。每轮合并都会使图表变得相当复杂,这让我得出两个结论:
- 只要我注意自己的步骤,不做任何愚蠢的事情,并且不试图弄清楚任何意义,这种分层分支的方式就可以工作所有分支的历史图。或者..
- 必须有一些更好、更合适的方法来做到这一点。
为了说明我的“问题”,我将给出一张图表,该图像是在创建这些分支、添加一些特定于分支的提交、挑选其中一些、添加并合并从 master 到所有分支的一个提交、提交或两个到特定分支,然后再进行一个从主到所有的合并。
我不知道,我喜欢简单,也许我不习惯看到像这样的难以理解的图表(恐怕它只会随着每次合并而变得复杂)。
我想我可以一直进行挑选,并拥有整洁的历史图表,但这听起来也不正确,因为我可能会连续进行多次提交,然后忘记将其中一个提交到所有其他分支。 ..
那么...您有什么想法、经验、建议不介意分享吗?
更新:我选择了对已接受答案的评论中描述的解决方案。感谢所有贡献者!
更新2:尽管它与这个问题没有紧密相关,最近我偶然发现了这种分支模型,它似乎适用于几乎任何有组织的开发周期,以 GIT 作为底层 DVCS。这真是一本好书。受到推崇的。
I'm using git on a daily basis for a while now, and this time I've run into a problem which I could describe like this.
I have a repository which holds entire website structure, and web root is in the root of the repository. Everything was fine until that was repository for a single site. However, that same repo is now used for several sites - basically the same site, in different languages, minor template tweaks, different graphics, etc. Those things are naturally versioned.
There is a master branch, which holds original source code of the site, and I'd like to have master (or some other branch) to hold code that is universal across all sites, as there will eventually be changes that are too site-specific to include in universal part of the repo.
Next, there is a branch for every single site which uses this source code. All those branches (say, site1, site2, and site3) are created from master branch, and each site clones correct branch.
Well, it seemed like a good idea, until I started making changes everywhere.
If I made a change on site1 branch, and I needed to copy that change to site2 branch, I would cherry-pick commit from one branch to another. Merging is out of the question there, as there are other changes on site1 branch which do not belong with site2 branch. Is there some other, more elegant solution for this kind of situation, or is that cherry-picking is exactly for this purpose?
Now, the real "problem" for me is when I change master, and then I want to copy all those changes to all branches. Naturally, considering the fact that all branches are descendants of master, and that I do want those changes in all site* branches, I switch to each branch and merge master.
This creates a pretty nasty-looking history for all branches. Each round of merges complicates graph considerably, which leads me to two conclusions:
- this way of layering branches can work as long as I watch my step and not do anything stupid, and not trying to get any sense out of all-branches history graph. Or..
- there has to be some better, more appropriate way to do it.
To illustrate my "problem", I'll give an image of graph that I got after creating those branches, adding few branch-specific commits, cherry-picking few of them, adding and merging one commit from master to all branches, commit or two to specific branches, and then one more master-to-all merge.
I don't know, I like simplicity, and maybe I'm not used to seeing hard-to-follow graphs like this one (which will only grow in complexity with every following merge, I'm afraid).
I guess I could do cherry-picking all the way, and have neat history graph, but that doesn't sound right either, since I might do several commits in a row, and then forget to pick one of them to all other branches...
So... Any ideas, experiences, suggestions that you wouldn't mind to share?
UPDATE: I choose a solution described in my comment on accepted answer. Thanks to everyone who contributed!
UPDATE 2: Even though it's not tightly related to this question, recently I stumbled upon this model of branching that appears to be suitable for pretty much any organized development cycle, with GIT as underlying DVCS. It's a really good read. Recommended.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
替代答案:
您可以将抽象从分支级别移动到存储库级别。使用主分支创建一个主存储库。为每个站点克隆此存储库。当对主分支进行更改时,将这些更改拉入每个站点存储库。这样,每个存储库只需要一个主分支。
原始答案:
当主分支更改后,您可以将其他分支重新设置到更新的主分支上。让我们假设您有基于 master 上的某些提交的 pl_site,并且该 master 已更改:
在重新基化 pl_site 后,它将如下所示:
请注意,重新基化版本的 pl_site 上的提交是新的。 pl_site 现在包含在 master 上所做的更改。
命令:
Alternate answer:
You could move the abstraction from branch level to repository level. Create one main repo with a master branch. Clone this repository for each site. When changes are made on the master branch, pull these changes into each site repo. This way you will only need one master branch per repo.
Original answer:
When the master branch has been changed you could rebase the other branches onto the updated master branch. Lets assume you have pl_site based on some commit on master and that master has changed:
After you have rebased pl_site, it will look like:
Note that the commits on rebased version of pl_site are new. pl_site now contains the changes that were made on master.
Commands:
我没有一个好的答案给你,因为你的问题很复杂,解决方案也很复杂。
选项 1:重构
您说过不同的站点“基本上是相同的站点”。因此,将它们移动到不同的项目,并将
main_site
单独保留在一个项目中。然后,其他站点将包含main_site
作为子项目。因此,对于横幅...
您的网站代码、配置脚本、部署脚本或其他任何内容将确保选择
images/banner.jpg
而不是master/images/banner.jpg
。也许当您部署站点时,首先复制 master/images,然后复制 images,也许您会做一些更复杂的事情。这可能需要大量工作。但是,当您查看历史记录时,您会得到如下信息:
选项 2:使用 Darcs
在 Darcs 中,您可以将补丁从一个分支移动到另一个分支。一些商业 VCS 或许也可以做到这一点。因此,您的分支将如下所示:
假设您要将补丁
en2
移植到德语站点。瞧。然而,这并不像看起来那么干净。 Darcs 爱好者会指出,这个补丁模型与我们的“将补丁移动到另一个分支”的概念模型相匹配,但是,这掩盖了这样一个事实:您仍然需要进行测试以确保
en2
当您将补丁放在de_site
上时,它不会破坏所有内容。例如,如果
en2
对代码中与de1
相同的部分进行了更改,会怎样?然后呢?无论您使用什么 VCS,都必须手动合并。对于像这样的每个明显情况,还有一种 VCS 无法检测到的情况,您必须自己检查。我的经验
当我第一次开始使用
git
时,git merge
似乎很神奇。然而,再多的 VCS 欺骗也无法掩盖这样一个事实:您的站点具有一些非常复杂的相互依赖关系。您可以重构您的站点以消除相互依赖性,或者希望您的 VCS 历史记录不会变得如此复杂以至于您无法再理解它。新分支、新项目和将内容重构到库中之间的权衡是一个微妙的权衡。维护大量补丁集比维护大量都使用公共库的项目要多得多,重构所需的(大量)工作可能很快就会得到回报。或者也可能不会。
I don't have a good answer for you, because your problem is complicated and has complicated solutions.
Option 1: Refactor
You said that the different sites are "basically the same site". So move them to different projects, and keep the
main_site
in a project by itself. The other sites will then includemain_site
as a subproject.So, for the banner...
Your web site code, configuration script, deployment script, or whatever will make sure that
images/banner.jpg
is chosen overmaster/images/banner.jpg
. Maybe when you deploy the sitemaster/images
gets copied first and thenimages
gets copied over it, maybe you do something more sophisticated.This might be a lot of work. However, when you look at the history, you'll get something like this:
Option 2: Use Darcs
In Darcs, you can move patches from branch to branch. Some commercial VCSs can probably do this too. So your branches would look like this:
Suppose that you want to port patch
en2
to the German site.Voila. However, this is not as clean as it looks. Darcs aficionados will point out that this patch model matches our conceptual model of "moving a patch to another branch", however, this glosses over the fact that you'll still have to test to make sure that the
en2
patch doesn't break everything when you put it onde_site
.For example, what if
en2
makes a change to the same part of the code asde1
? What then? You have to merge manually, no matter what VCS you are using. For every obvious case like this, there is another case which the VCS won't detect and you'll have to check it yourself.My experience
When I first started using
git
, it seemed likegit merge
was magic. However, no amount of VCS trickery is going to hide the fact that your site has some very complicated interdependencies. You can either refactor your site to remove the interdependencies, or hope that your VCS history doesn't become so complicated that you can no longer understand it.The tradeoff between new branches, new projects, and refactoring things into libraries is a delicate tradeoff. Maintaining a large collection of patchsets is much more work than maintaining a large collection of projects which all use a common library, the (large) amount of work necessary to refactor may pay off quickly. Or it may not.