使用Git跟踪第三方代码

hop*_*pla 24 git

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

你们真的很善于对此有所了解并帮助我解决具体的用例吗?对于以下具体问题,最佳解决方案是什么?(我不会试图概括我的问题,因为我可能会对事情做出错误的假设,特别是因为我对这一切都很新......)

我正在Django(Python中的Web框架)中构建一个网站.现在,有许多第三方插件可供Django使用(Django称之为"应用程序"),您可以放入项目中.其中一些应用程序可能需要一些修改才能像我想要的那样工作.但是,如果您开始对第三方代码进行修改,则会引入在更新版本出现时更新该代码的问题,同时保留您的本地修改.

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

/trunk
  ...
  /apps
    /blog-app
  ...
/tags
  ...
/branches
  ...
/vendor
  /django-apps
    /blog-app
      /1.2
      /1.3
      /current
    /other-app
      /3.2
      /current
Run Code Online (Sandbox Code Playgroud)

在这种情况下,/ trunk/apps/blog-app将被复制到/ vendor/django-apps/blog-app中的一个标签.说它是v1.2.而且我现在想将我的版本在trunk中升级到v1.3.如您所见,我已将/ vendor/django-apps/blog-app/current(使用svn_load_dirs)和'tagged'(svn copy)更新为/vendor/django-apps/blog-app/1.3.现在我可以通过svn合并/ 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)

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

让我重新讨论一下这些要求:

  • 我必须能够将外部代码放在树中的任意位置
  • 我必须能够修改外部代码并在我的Git存储库中保留(提交)这些修改
  • 如果发布新版本,我必须能够轻松更新外部代码,同时保留我的更改

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

  • 我最好不要像svn_load_dirs这样做.我认为应该可以直接从他们的存储库跟踪应用程序及其更新(大多数第三方Django应用程序保存在Subversion中).能够在发布版本之间查看单个提交消息,这给了我额外的好处.并且更容易修复合并冲突,因为我可以处理许多小提交而不是svn_load_dirs创建的一个人为提交.我想在Subversion中使用svn:externals可以做到这一点,但我以前从未使用过它...

可以使用两种方法的组合的解决方案将更加可取,因为可能有应用程序开发人员不使用源代码管理或不公开他们的回购.(意思是svn_load_dirs之类的行为和直接从Subversion重新定位(或其他Git)跟踪)

我想我要么必须使用子树,子模块,rebase,分支......或者这些的组合,但是如果我知道哪一个或者怎么做就打倒我:S

我急切地等待你的回复!回复时请尽可能详细,因为我已经很难理解在线发现的其他例子.

提前致谢

emk*_*emk 27

这里有两个不同的问题:

  1. 你如何维护远程项目的本地分支,以及
  2. 如何在自己的树中保留远程项目的副本?

问题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
Run Code Online (Sandbox Code Playgroud)

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

git pull upstream master
Run Code Online (Sandbox Code Playgroud)

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

git submodule add ssh://.../my-forked-foo.git local/path/for/foo
Run Code Online (Sandbox Code Playgroud)

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

你可能会发现git子模块有时候有点棘手.以下是一些需要注意的事项:

  1. 在提交父级之前始终提交子模块.
  2. 在推送父模板之前始终按下子模块.
  3. 在提交之前,确保子模块的HEAD指向分支.(如果您是bash用户,我建议使用git-completion将当前分支名称放在提示符中.)
  4. 切换分支或拉动更改后始终运行'git submodule update'.

你可以使用我的一个同事创建的别名在一定程度上解决(4):

git config --global alias.pull-recursive '!git pull && git submodule update --init'
Run Code Online (Sandbox Code Playgroud)

...然后运行:

git pull-recursive
Run Code Online (Sandbox Code Playgroud)

如果git子模块如此棘手,有什么优势?

  1. 您可以在不签出子模块的情况下查看主项目.当子模块很大,并且在某些平台上不需要它们时,这很有用.
  2. 如果您有经验的git用户,则可以使用子模块的多个分叉,并将它们与主项目的不同分支链接.
  3. 总有一天,有人可能会修复git子模块以更优雅地工作.子模块实现中最深的部分实际上非常好; 它只是被破坏的高级工具.

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

如果您不想使用git子模块,您可能需要查看git merge的子树策略.这将一切都保存在一个存储库中

如果上游存储库使用Subversion怎么办?

如果你知道如何使用git svn,这很容易:

git svn clone -s https://example.com/foo
cd foo
git remote add origin ssh://.../my-forked-foo.git
git push origin
Run Code Online (Sandbox Code Playgroud)

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

git push origin master:local-fork
git checkout -b local-fork origin/local-fork
Run Code Online (Sandbox Code Playgroud)

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

git svn fetch
git merge trunk
Run Code Online (Sandbox Code Playgroud)

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

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

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

git svn init -s https://example.com/foo
git svn fetch
Run Code Online (Sandbox Code Playgroud)

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