使用 Git 跟踪第 3 方代码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/677393/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-19 03:37:29  来源:igfitidea点击:

Tracking 3rd party code with Git

git

提问by hopla

I can't seem to grok the different solutions I've found and studied for tracking external code. Let alone understand how to apply them to my use case...

我似乎无法理解我为跟踪外部代码而发现和研究的不同解决方案。更不用说了解如何将它们应用于我的用例......

Would you guys be so kind to shed some light on this and help me with my specific use case? What would be the best solution for the following, concrete problem? (I'm not gonna attempt to generalize my problem, since I might make wrong assumptions about stuff, especially since I'm so new with all this...)

你们能不能帮我解释一下这个问题并帮助我解决我的具体用例?以下具体问题的最佳解决方案是什么?(我不会试图概括我的问题,因为我可能会对事物做出错误的假设,尤其是因为我对这一切都很陌生......)

I'm building a website in Django (a web framework in Python). Now, there are a lot of 3rd party plugins available for use with Django (Django calls them 'apps'), that you can drop in your project. Some of these apps might require a bit of modification to get working like I want them. But if you start making modifications to 3rd party code you introduce the problem of updating that code when newer versions appear AND at the same time keeping your local modifications.

我正在 Django 中构建一个网站(Python 中的 Web 框架)。现在,有很多 3rd 方插件可用于 Django(Django 将它们称为“应用程序”),您可以将它们放入您的项目中。其中一些应用程序可能需要进行一些修改才能像我想要的那样工作。但是,如果您开始对第 3 方代码进行修改,则会在出现新版本时更新该代码并同时保留您的本地修改。

So, the way I would do that in Subversion is by using vendor branches. My repository layout would look like this:

所以,我在 Subversion 中这样做的方法是使用供应商分支。我的存储库布局如下所示:

/trunk
  ...
  /apps
    /blog-app
  ...
/tags
  ...
/branches
  ...
/vendor
  /django-apps
    /blog-app
      /1.2
      /1.3
      /current
    /other-app
      /3.2
      /current

In this case /trunk/apps/blog-app would have been svn copy'd of one of the tags in /vendor/django-apps/blog-app. Say that it was v1.2. And that I now want to upgrade my version in trunk to v1.3. As you can see, I have already updated /vendor/django-apps/blog-app/current (using svn_load_dirs) and 'tagged' (svn copy) it as /vendor/django-apps/blog-app/1.3. Now I can update /trunk/apps/blog-app by svn merge'ing the changes between /vendor/django-apps/blog-app/1.2 and /vendor/django-apps/blog-app/1.3 on /trunk/apps/blog-app. This will keep my local changes. (for people unknown with this process, it is described in the Subversion handbook: http://svnbook.red-bean.com/en/1.5/svn.advanced.vendorbr.html)

在这种情况下,/trunk/apps/blog-app 将被 svn 复制到 /vendor/django-apps/blog-app 中的标签之一。说它是 v1.2。而且我现在想将主干中的版本升级到 v1.3。如您所见,我已经更新了 /vendor/django-apps/blog-app/current(使用 svn_load_dirs)并将其“标记”(svn copy)为 /vendor/django-apps/blog-app/1.3。现在我可以更新 /trunk/apps/blog-app 通过在 /trunk/apps 上合并 /vendor/django-apps/blog-app/1.2 和 /vendor/django-apps/blog-app/1.3 之间的变化来更新 /trunk/apps/blog-app /博客应用程序。这将保留我的本地更改。(对于不知道这个过程的人,它在 Subversion 手册中有描述:http: //svnbook.red-bean.com/en/1.5/svn.advanced.vendorbr.html

Now I want to do this whole process in Git. How can I do this?

现在我想在 Git 中完成整个过程。我怎样才能做到这一点?

Let me re-iterate the requirements:

让我重申一下要求:

  • I must be able to place the external code in an arbitrary position in the tree
  • I must be able to modify the external code and keep (commit) these modifications in my Git repos
  • I must be able to easily update the external code, should a new version be released, whilst keeping my changes
  • 我必须能够将外部代码放置在树中的任意位置
  • 我必须能够修改外部代码并在我的 Git 存储库中保留(提交)这些修改
  • 如果发布新版本,我必须能够轻松更新外部代码,同时保留我的更改

Extra (for bonus points ;-) ):

额外(奖励积分;-)):

  • Preferably I want to do this without something like svn_load_dirs. I think it should be possible to track the apps and their updates straight from their repository (most 3rd party Django apps are kept in Subversion). Giving me the added benefit of being able to view individual commit messages between releases. And fixing merge conflicts more easily since I can deal with a lot of small commits instead of the one artificial commit created by svn_load_dirs. I think one would do this with svn:externals in Subversion, but I have never worked with that before...
  • 最好我想在没有 svn_load_dirs 之类的东西的情况下做到这一点。我认为应该可以直接从他们的存储库中跟踪应用程序及其更新(大多数 3rd 方 Django 应用程序都保存在 Subversion 中)。给我一个额外的好处,即能够在版本之间查看单独的提交消息。并且更容易修复合并冲突,因为我可以处理很多小的提交,而不是由 svn_load_dirs 创建的一个人工提交。我认为人们会在 Subversion 中使用 svn:externals 来做到这一点,但我以前从未使用过...

A solution where a combination of both methods could be used would be even more preferable, since there might be app developers who don't use source control or don't make their repos available publicly. (Meaning both svn_load_dirs-like behavior and tracking straight from a Subversion reposity (or another Git))

可以使用两种方法组合的解决方案会更可取,因为可能有应用程序开发人员不使用源代码管理或不公开其存储库。(意味着类似于 svn_load_dirs 的行为和直接从 Subversion 存储库(或另一个 Git)跟踪)

I think I would either have to use subtrees, submodules, rebase, branches, ... or a combination of those, but smack down me if I know which one(s) or how do to it :S

我想我要么必须使用子树、子模块、rebase、分支,...或这些的组合,但如果我知道哪个或如何使用它,请打倒我:S

I'm eagerly awaiting your responses! Please be as verbose as possible when replying, since I already had a hard time understanding other examples found online.

我急切地等待您的回复!回复时请尽可能详细,因为我已经很难理解网上找到的其他示例。

Thanks in advance

提前致谢

回答by emk

There are two separate problems here:

这里有两个不同的问题:

  1. How do you maintain local forks of remote projects, and
  2. How do you keep a copy of remote projects in your own tree?
  1. 你如何维护远程项目的本地分支,以及
  2. 您如何在自己的树中保留远程项目的副本?

Problem 1 is pretty easy by itself. Just do something like:

问题 1 本身很容易。只需执行以下操作:

git clone git://example.com/foo.git
cd foo
git remote add upstream git://example.com/foo.git
git remote rm origin
git remote add origin ssh://.../my-forked-foo.git
git push origin

You can then work on your forked repository normally. When you want to merge in upstream changes, run:

然后您可以正常处理您的分叉存储库。如果要合并上游更改,请运行:

git pull upstream master

As for problem 2, one option is to use submodules. For this, cd into your main project, and run:

对于问题 2,一种选择是使用子模块。为此, cd 进入您的主项目,然后运行:

git submodule add ssh://.../my-forked-foo.git local/path/for/foo

If I use git submodules, what do I need to know?

如果我使用 git 子模块,我需要知道什么?

You may find git submodules to be a little bit tricky at times. Here are some things to keep in mind:

您可能会发现 git 子模块有时有点棘手。以下是一些需要牢记的事项:

  1. Always commit the submodule before committing the parent.
  2. Always push the submodule before pushing the parent.
  3. Make sure that the submodule's HEAD points to a branch before committing to it. (If you're a bash user, I recommend using git-completionto put the current branch name in your prompt.)
  4. Alwaysrun 'git submodule update' after switching branches or pulling changes.
  1. 在提交父模块之前总是提交子模块。
  2. 在推送父模块之前总是推送子模块。
  3. 在提交之前确保子模块的 HEAD 指向一个分支。(如果您是 bash 用户,我建议您使用git-completion将当前分支名称放在您的提示中。)
  4. 在切换分支或拉取更改后始终运行“git submodule update”。

You can work around (4) to a certain extent by using an alias created by one of my coworkers:

通过使用我的一位同事创建的别名,您可以在一定程度上解决 (4) 问题:

git config --global alias.pull-recursive '!git pull && git submodule update --init'

...and then running:

...然后运行:

git pull-recursive

If git submodules are so tricky, what are the advantages?

如果 git submodules 这么棘手,有什么好处?

  1. You can check out the main project without checking out the submodules. This is useful when the submodules are huge, and you don't need them on certain platforms.
  2. If you have experienced git users, it's possible to have multiple forks of your submodule, and link them with different forks of your main project.
  3. Someday, somebody might actually fix git submodules to work more gracefully. The deepest parts of the submodule implementation are actually quite good; it's just the upper-level tools that are broken.
  1. 您可以检出主项目而无需检出子模块。当子模块很大并且在某些平台上不需要它们时,这很有用。
  2. 如果您有经验的 git 用户,您的子模块可能有多个分支,并将它们与主项目的不同分支链接起来。
  3. 总有一天,有人可能会修复 git 子模块以使其更优雅地工作。子模块实现最深的部分其实还不错;只是上层工具坏了。

git submodules aren't for me. What next?

git 子模块不适合我。接下来是什么?

If you don't want to use git submodules, you might want to look into git merge's subtree strategy. This keeps everything in one repository.

如果您不想使用 git submodules,您可能需要查看git merge 的 subtree strategy。这将所有内容保存在一个存储库中。

What if the upstream repository uses Subversion?

如果上游存储库使用 Subversion 会怎样?

This is pretty easy if you know how to use git svn:

如果您知道如何使用 git svn,这将非常简单:

git svn clone -s https://example.com/foo
cd foo
git remote add origin ssh://.../my-forked-foo.git
git push origin

Then set up a local tracking branch in git.

然后在 git 中设置一个本地跟踪分支。

git push origin master:local-fork
git checkout -b local-fork origin/local-fork

Then, to merge from upstream, run:

然后,要从上游合并,请运行:

git svn fetch
git merge trunk

(I haven't tested this code, but it's more-or-less how we maintain one submodule with an upstream SVN repository.)

(我还没有测试过这段代码,但我们或多或少是如何维护一个带有上游 SVN 存储库的子模块的。)

Don't use git svn rebase, because it will make it very difficult to use git submodule in the parent project without losing data. Just treat the Subversion branches as read-only mirrors of upstream, and merge from them explicitly.

不要使用 git svn rebase,因为这会让在父项目中使用 git submodule 而不丢失数据变得非常困难。只需将 Subversion 分支视为上游的只读镜像,并明确地从它们合并。

If you need to access the upstream Subversion repository on another machine, try:

如果您需要访问另一台机器上的上游 Subversion 存储库,请尝试:

git svn init -s https://example.com/foo
git svn fetch

You should then be able to merge changes from upstream as before.

然后,您应该能够像以前一样合并来自上游的更改。

回答by hopla

I've looked around a bit more and stumbled upon Braid. It's a tool that automates vendor branches in Git. It can use Git or SVN repos.

我环顾四周,偶然发现了Braid。它是一种在 Git 中自动化供应商分支的工具。它可以使用 Git 或 SVN 存储库。

By crawling through the source I found out that it uses the subtree strategy. And seems to make it really simple! Plus, it seems to fulfill all my requirements!

通过浏览源代码,我发现它使用了子树策略。而且似乎让它变得非常简单!另外,它似乎满足了我的所有要求!

Before I jump in and use it: does anyone here have any experience with Braid? I would like to find out about possible cons if there are any. Also, if you haven't used Braid, but have some expertise in Git, what do you think about it, at first sight?

在我开始使用它之前:这里有人有使用 Braid 的经验吗?如果有的话,我想找出可能的缺点。另外,如果你没有使用过 Braid,但对 Git 有一定的专业知识,你怎么看它,乍一看?

回答by Grégtheitroade Cachet

I use git submodules to track reusable apps in my Django projects, but it is kind of messy in the long run.

我使用 git 子模块来跟踪我的 Django 项目中的可重用应用程序,但从长远来看它有点混乱。

It is messy for deployment because you can't get a clean archive of the whole tree (with submodules) using git archive. There are some tricks, but nothing perfect. Besides, the submodule update mecanism is not that good for working with submodules branches.

部署很麻烦,因为您无法使用 git archive 获得整个树(带有子模块)的干净存档。有一些技巧,但没有完美的。此外,子模块更新机制不适用于处理子模块分支。

You might have to take a look at virtualenv and pip, because they had some recent improvements in order to work with external repositories.

您可能需要查看 virtualenv 和 pip,因为它们最近进行了一些改进,以便与外部存储库一起使用。

pip : http://pip.openplans.org/and working with pip/virtualenv : http://www.b-list.org/weblog/2008/dec/15/pip/

pip : http://pip.openplans.org/并使用 pip/virtualenv : http://www.b-list.org/weblog/2008/dec/15/pip/

回答by michel.iamit

I think my answer to to another questions gives exactly a nice solution for the problem described here, without going in to the hell of submodules (which I have tried, but does not even get close to the svn:externals I was used to)

我认为我对另一个问题的回答为这里描述的问题提供了一个很好的解决方案,而无需进入地狱的子模块(我已经尝试过,但甚至没有接近我习惯的 svn:externals)

Still, have a look at this answer: Do you version control the invidual apps or the whole project or both?

不过,看看这个答案: 你是对单个应用程序还是整个项目进行版本控制,还是两者兼而有之?

Before deleting my answer again, I was not aware I couldn't copy my own answer to another question, even if I Am convinced it is usefull as an answer. Sorry, but give this answer a try, it really is a nice solution. So I hope I Am allowed to refer to my own anser to another question.

在再次删除我的答案之前,我不知道我不能将自己的答案复制到另一个问题,即使我确信它作为答案有用。抱歉,请尝试一下这个答案,这确实是一个不错的解决方案。所以我希望我可以参考我自己的另一个问题的答案。