Git
英语 ▾ 主题 ▾ 最新版本 ▾ git-svn 最后更新于 2.47.0

名称

git-svn - Subversion 存储库和 Git 之间的双向操作

概要

git svn <command> [<options>] [<arguments>]

描述

git svn 是 Subversion 和 Git 之间变更集的简单通道。它在 Subversion 和 Git 存储库之间提供双向的变更流。

git svn 可以跟踪标准的 Subversion 存储库,遵循常见的 “trunk/branches/tags” 布局,使用 --stdlayout 选项。它也可以使用 -T/-t/-b 选项(参见下面 init 的选项,以及 clone 命令)跟踪任何布局中的分支和标签。

一旦跟踪了 Subversion 存储库(使用上述任何方法),Git 存储库可以使用 fetch 命令从 Subversion 更新,Subversion 可以使用 dcommit 命令从 Git 更新。

命令

init

使用 git svn 的额外元数据目录初始化一个空的 Git 存储库。Subversion URL 可以作为命令行参数指定,或者作为 -T/-t/-b 的完整 URL 参数指定。可选地,可以指定要操作的目标目录作为第二个参数。通常此命令会初始化当前目录。

-T<trunk-subdir>
--trunk=<trunk-subdir>
-t<tags-subdir>
--tags=<tags-subdir>
-b<branches-subdir>
--branches=<branches-subdir>
-s
--stdlayout

这些是 init 的可选命令行选项。每个标志都可以指向一个相对的存储库路径 (--tags=project/tags) 或一个完整的 URL (--tags=https://foo.org/project/tags)。如果您的 Subversion 存储库将标签或分支放在多个路径下,您可以指定多个 --tags 和/或 --branches 选项。选项 --stdlayout 是设置 trunk、tags、branches 作为相对路径的简写方式,这是 Subversion 的默认值。如果也指定了其他任何选项,则它们优先。

--no-metadata

在 [svn-remote] 配置中设置 noMetadata 选项。不建议使用此选项,请在使用此选项之前阅读本手册页中的 svn.noMetadata 部分。

--use-svm-props

在 [svn-remote] 配置中设置 useSvmProps 选项。

--use-svnsync-props

在 [svn-remote] 配置中设置 useSvnsyncProps 选项。

--rewrite-root=<URL>

在 [svn-remote] 配置中设置 rewriteRoot 选项。

--rewrite-uuid=<UUID>

在 [svn-remote] 配置中设置 rewriteUUID 选项。

--username=<user>

对于 SVN 处理身份验证的传输(http、https 和普通 svn),指定用户名。对于其他传输(例如 svn+ssh://),您必须在 URL 中包含用户名,例如 svn+ssh://[email protected]/project

--prefix=<prefix>

这允许您指定一个前缀,该前缀会附加到远程名称的前面,如果指定了 trunk/branches/tags。前缀不会自动包含尾部斜杠,因此请确保您在参数中包含一个,如果您想要这样做。如果指定了 --branches/-b,则前缀必须包含尾部斜杠。无论如何,强烈建议设置前缀(带尾部斜杠),因为您的 SVN 跟踪引用将位于 “refs/remotes/$prefix/” 中,这与 Git 自身的远程跟踪引用布局兼容(refs/remotes/$remote/)。如果您希望跟踪多个共享公共存储库的项目,设置前缀也很有用。默认情况下,前缀设置为 origin/

注意
在 Git v2.0 之前,默认前缀为空字符串(无前缀)。这意味着 SVN 跟踪引用放在 “refs/remotes/*” 中,这与 Git 自身远程跟踪引用的组织方式不兼容。如果您仍然想要旧的默认值,可以通过在命令行中传递 --prefix "" 来获得它(如果您的 Perl 的 Getopt::Long < v2.37,--prefix="" 可能不起作用)。
--ignore-refs=<regex>

传递给 initclone 时,此正则表达式将作为配置键保留。有关 --ignore-refs 的描述,请参见 fetch

--ignore-paths=<regex>

传递给 initclone 时,此正则表达式将作为配置键保留。有关 --ignore-paths 的描述,请参见 fetch

--include-paths=<regex>

传递给 initclone 时,此正则表达式将作为配置键保留。有关 --include-paths 的描述,请参见 fetch

--no-minimize-url

当跟踪多个目录(使用 --stdlayout、--branches 或 --tags 选项)时,git svn 将尝试连接到 Subversion 存储库的根目录(或允许的最高级别)。此默认值允许在整个项目在存储库内移动时更好地跟踪历史记录,但可能会在对存储库施加读取访问限制的地方造成问题。传递 --no-minimize-url 将允许 git svn 按原样接受 URL,而不会尝试连接到更高级别的目录。仅跟踪一个 URL/分支时,此选项默认关闭(这没什么用)。

fetch

从我们正在跟踪的 Subversion 远程服务器中获取未获取的修订版。[svn-remote "…​"] 部分的名称可以在 $GIT_DIR/config 文件中作为可选的命令行参数指定。

这会自动更新 rev_map(如果需要)(有关详细信息,请参见下面 FILES 部分中的 $GIT_DIR/svn/**/.rev_map.*)。

--localtime

将 Git 提交时间存储在本地时区而不是 UTC 中。这使得 git log(即使没有 --date=local)显示与 svn log 在本地时区中显示的相同时间。

这不会影响与您克隆的 Subversion 存储库的互操作性,但如果您希望您的本地 Git 存储库能够与其他人的本地 Git 存储库互操作,则不要使用此选项,或者您应该都在同一个本地时区中使用它。

--parent

仅从当前 HEAD 的 SVN 父级获取。

--ignore-refs=<regex>

忽略与 Perl 正则表达式匹配的分支或标签的引用。可以使用 “否定前瞻断言” 如 ^refs/remotes/origin/(?!tags/wanted-tag|wanted-branch).*$ 来仅允许某些引用。

config key: svn-remote.<name>.ignore-refs

如果设置了 ignore-refs 配置键并且也给出了命令行选项,则将使用两个正则表达式。

--ignore-paths=<regex>

这允许您指定一个 Perl 正则表达式,该表达式将导致从 SVN 中检出时跳过所有匹配的路径。--ignore-paths 选项应匹配给定存储库的每次获取(包括由于克隆dcommitrebase 等导致的自动获取)。

config key: svn-remote.<name>.ignore-paths

如果设置了 ignore-paths 配置键并且也给出了命令行选项,则将使用两个正则表达式。

示例

跳过每次获取的“doc*”目录
--ignore-paths="^doc"
跳过一级目录的“branches”和“tags”
--ignore-paths="^[^/]+/(?:branches|tags)"
--include-paths=<regex>

这允许您指定一个 Perl 正则表达式,该表达式将导致从 SVN 中检出时仅包含匹配的路径。--include-paths 选项应匹配给定存储库的每次获取(包括由于克隆dcommitrebase 等导致的自动获取)。--ignore-paths 优先于 --include-paths

config key: svn-remote.<name>.include-paths
--log-window-size=<n>

扫描 Subversion 历史记录时,每次请求获取 <n> 个日志条目。默认值为 100。对于非常大的 Subversion 存储库,克隆/获取可能需要更大的值才能在合理的时间内完成。但是,过大的值可能会导致更高的内存使用量和请求超时。

克隆

运行初始化获取。它将根据传递给它的 URL 的基本名称自动创建一个目录;或者,如果传递了第二个参数;它将在该目录内创建一个目录并工作。它接受初始化获取命令接受的所有参数;除了 --fetch-all--parent。克隆存储库后,获取命令将能够更新修订版而不会影响工作树;并且rebase 命令将能够使用最新更改更新工作树。

--preserve-empty-dirs

在本地 Git 存储库中为从 Subversion 获取的每个空目录创建一个占位符文件。这包括通过从 Subversion 存储库中删除所有条目(但不包括目录本身)而变为空的目录。占位符文件也会被跟踪,并在不再需要时被删除。

--placeholder-filename=<filename>

设置由 --preserve-empty-dirs 创建的占位符文件的名称。默认值:“.gitignore”

rebase

这将从当前 HEAD 的 SVN 父级获取修订版,并将当前(未提交到 SVN)工作重新设置到该修订版。

这与 svn updategit pull 的工作方式类似,只是它使用git rebase 而不是git merge 来保留线性历史记录,以便于使用git svn 进行 dcommit。

这接受git svn fetchgit rebase 接受的所有选项。但是,--fetch-all 只从当前的 [svn-remote] 获取,而不是从所有 [svn-remote] 定义获取。

git rebase 一样;这要求工作树干净并且没有未提交的更改。

这会自动更新 rev_map(如果需要)(有关详细信息,请参见下面 FILES 部分中的 $GIT_DIR/svn/**/.rev_map.*)。

-l
--local

不要远程获取;只对来自上游 SVN 的最后一次获取的提交运行git rebase

dcommit

将当前分支的每个差异直接提交到 SVN 存储库,然后重新设置基线或重置(取决于 SVN 和头部之间是否存在差异)。这将为 Git 中的每个提交在 SVN 中创建一个修订版。

当可选的 Git 分支名称(或 Git 提交对象名称)作为参数指定时,子命令将在指定的分支上工作,而不是在当前分支上工作。

建议使用dcommit 而不是set-tree(如下)。

--no-rebase

提交后,不要重新设置基线或重置。

--commit-url <URL>

提交到此 SVN URL(完整路径)。这旨在允许使用一种传输方法(例如,svn://http:// 用于匿名读取)创建的现有git svn 存储库在用户后来获得对另一种传输方法的访问权限(例如,svn+ssh://https://)进行提交时被重用。

config key: svn-remote.<name>.commiturl
config key: svn.commiturl (overwrites all svn-remote.<name>.commiturl options)

请注意,commiturl 配置键的 SVN URL 包含 SVN 分支。如果您希望为整个 SVN 存储库设置提交 URL,请使用 svn-remote.<name>.pushurl 代替。

强烈建议不要将此选项用于任何其他目的(不要问)。

--mergeinfo=<mergeinfo>

在 dcommit 期间添加给定的合并信息(例如,--mergeinfo="/branches/foo:1-10")。所有 svn 服务器版本都可以存储此信息(作为属性),从版本 1.5 开始的 svn 客户端可以使用它。要指定来自多个分支的合并信息,请在分支之间使用单个空格字符(--mergeinfo="/branches/foo:1-10 /branches/bar:3,5-6,8"

config key: svn.pushmergeinfo

此选项将导致 git-svn 在可能的情况下尝试自动填充 SVN 存储库中的 svn:mergeinfo 属性。目前,这只能在 dcommit 非快进合并时完成,其中除第一个之外的所有父级都已经推送到 SVN。

--interactive

询问用户确认是否应该将补丁集实际发送到 SVN。对于每个补丁,您可以回答“yes”(接受此补丁)、“no”(丢弃此补丁)、“all”(接受所有补丁)或“quit”。

如果答案是“no”或“quit”,git svn dcommit 将立即返回,而不会将任何内容提交到 SVN。

分支

在 SVN 存储库中创建一个分支。

-m
--message

允许指定提交消息。

-t
--tag

通过使用 tags_subdir 而不是在 git svn init 期间指定的 branches_subdir 来创建标签。

-d<path>
--destination=<path>

如果向初始化克隆命令提供了多个 --branches(或 --tags)选项,则必须提供要在 SVN 存储库中创建的分支(或标签)的位置。<path> 指定用于创建分支或标签的路径,并且应与配置的分支或标签 refspec 的左侧的模式匹配。您可以使用以下命令查看这些 refspec

git config --get-all svn-remote.<name>.branches
git config --get-all svn-remote.<name>.tags

其中 <name> 是 SVN 存储库的名称,如初始化的 -R 选项(或默认情况下为“svn”)指定。

--username

指定 SVN 用户名以执行提交。此选项将覆盖用户名配置属性。

--commit-url

使用指定的 URL 连接到目标 Subversion 存储库。这在源 SVN 存储库为只读的情况下很有用。此选项将覆盖配置属性commiturl

git config --get-all svn-remote.<name>.commiturl
--parents

创建父文件夹。此参数等效于 svn cp 命令中的 --parents 参数,对于非标准存储库布局很有用。

标签

在 SVN 存储库中创建一个标签。这是branch -t 的简写形式。

日志

这应该让您在 svn 用户引用 -r/--revision 号码时轻松查找 svn 日志消息。

支持来自“svn log” 的以下功能

-r <n>[:<n>]
--revision=<n>[:<n>]

受支持,非数字参数不受支持:HEAD、NEXT、BASE、PREV 等…​

-v
--verbose

它与 svn log 中的 --verbose 输出不完全兼容,但相当接近。

--limit=<n>

与 --max-count 不同,它不统计合并的/排除的提交

--incremental

支持

新功能

--show-commit

也显示 Git 提交 sha1。

--oneline

我们版本的 --pretty=oneline

注意
SVN 本身只以 UTC 存储时间,没有其他东西。常规的 svn 客户端会将 UTC 时间转换为本地时间(或基于 TZ= 环境)。此命令具有相同的行为。

任何其他参数都会直接传递给git log

责备

显示哪个修订版和作者最后修改了文件的每一行。默认情况下,此模式的输出与“svn blame” 的输出格式兼容。与 SVN blame 命令一样,工作树中的本地未提交更改会被忽略;HEAD 修订版中文件的版本会带注释。未知参数会直接传递给git blame

--git-format

以与git blame 相同的格式产生输出,但使用 SVN 修订版号而不是 Git 提交哈希。在此模式下,尚未提交到 SVN 的更改(包括本地工作副本编辑)将显示为修订版 0。

查找修订版

当给定一个形式为rN的 SVN 版本号时,返回相应的 Git 提交哈希值(可选地,后面可以跟着一个树状对象来指定应该搜索哪个分支)。当给定一个树状对象时,返回相应的 SVN 版本号。

-B
--before

如果给定一个 SVN 版本号,则不要求完全匹配,而是找到对应于 SVN 仓库(在当前分支上)在指定版本号状态下的提交。

-A
--after

如果给定一个 SVN 版本号,则不要求完全匹配;如果没有完全匹配,则返回在历史记录中向前搜索的最近匹配。

set-tree

您应该考虑使用dcommit而不是此命令。将指定的提交或树对象提交到 SVN。这依赖于您的导入提取数据是最新的。这在提交到 SVN 时绝对不尝试进行修补,它只是用树或提交中指定的那些文件覆盖文件。所有合并都假定独立于git svn函数进行。

create-ignore

递归地查找目录上的 svn:ignore 和 svn:global-ignores 属性,并创建匹配的 .gitignore 文件。生成的文件会被暂存以进行提交,但不会被提交。使用 -r/--revision 来引用特定的版本。

show-ignore

递归地查找并列出目录上的 svn:ignore 和 svn:global-ignores 属性。输出适合附加到 $GIT_DIR/info/exclude 文件。

mkdirs

尝试根据 $GIT_DIR/svn/<refname>/unhandled.log 文件中的信息重新创建核心 Git 无法跟踪的空目录。在使用 "git svn clone" 和 "git svn rebase" 时,空目录会自动重新创建,因此 "mkdirs" 旨在用于 "git checkout" 或 "git reset" 等命令之后。(有关更多信息,请参阅 svn-remote.<name>.automkdirs 配置文件选项。)

commit-diff

提交两个来自命令行的树状对象参数的差异。此命令不依赖于在git svn init-ed 仓库内。此命令接受三个参数,(a) 要与之比较的原始树,(b) 新的树结果,(c) 目标 Subversion 仓库的 URL。如果您从一个git svn感知仓库(已使用git svninit-ed)工作,则可以省略最后一个参数(URL)。为此需要 -r<revision> 选项。

提交消息直接通过-m-F选项提供,或者通过标签或提交间接提供,当第二个树状对象表示这样一个对象时,或者通过调用编辑器请求它(请参阅下面的--edit选项)。

-m <msg>
--message=<msg>

使用给定的msg作为提交消息。此选项禁用--edit选项。

-F <filename>
--file=<filename>

从给定的文件中获取提交消息。此选项禁用--edit选项。

info

显示有关文件或目录的信息,类似于 ‘svn info’ 提供的信息。目前不支持 -r/--revision 参数。使用 --url 选项仅输出URL: 字段的值。

proplist

列出 Subversion 仓库中存储在给定文件或目录上的属性。使用 -r/--revision 来引用特定的 Subversion 版本。

propget

获取作为第一个参数给出的 Subversion 属性,用于文件。可以使用 -r/--revision 指定特定版本。

propset

将作为第一个参数给出的 Subversion 属性设置为作为第二个参数给出的值,用于作为第三个参数给出的文件。

示例

git svn propset svn:keywords "FreeBSD=%H" devel/py-tipper/Makefile

这将为文件devel/py-tipper/Makefile将属性svn:keywords设置为FreeBSD=%H

show-externals

显示 Subversion 外部。使用 -r/--revision 指定特定的版本。

gc

压缩 $GIT_DIR/svn/<refname>/unhandled.log 文件并删除 $GIT_DIR/svn/<refname>/index 文件。

reset

撤消fetch对指定版本的影响。这允许您重新fetch SVN 版本。通常,SVN 版本的内容永远不会改变,reset 应该是不必要的。但是,如果 SVN 权限发生更改,或者您更改了 --ignore-paths 选项,则fetch可能会失败,并出现 "not found in commit"(文件以前不可见)或 "checksum mismatch"(错过修改)错误。如果问题文件不能永远忽略(使用 --ignore-paths),修复仓库的唯一方法是使用reset

仅更改 rev_map 和 refs/remotes/git-svn(有关详细信息,请参阅下面 FILES 部分中的$GIT_DIR/svn/**/.rev_map.*)。在reset之后,执行fetch,然后执行git resetgit rebase,将本地分支移动到新树上。

-r <n>
--revision=<n>

指定要保留的最新版本。所有后续版本都将被丢弃。

-p
--parent

也丢弃指定的版本,保留最近的父版本。

示例

假设您在 "master" 中有本地更改,但您需要重新提取 "r2"。

    r1---r2---r3 remotes/git-svn
                \
                 A---B master

修复导致 "r2" 在第一步中不完整的 ignore-paths 或 SVN 权限问题。然后

git svn reset -r2 -p
git svn fetch
    r1---r2'--r3' remotes/git-svn
      \
       r2---r3---A---B master

然后使用git rebase修复 "master"。不要使用git merge,否则您的历史记录将与将来的dcommit不兼容!

git rebase --onto remotes/git-svn A^ master
    r1---r2'--r3' remotes/git-svn
                \
                 A'--B' master

选项

--shared[=(false|true|umask|group|all|world|everybody)]
--template=<template-directory>

仅与init命令一起使用。这些将直接传递给git init

-r <arg>
--revision <arg>

fetch命令一起使用。

这允许支持部分/截断历史的版本范围。$NUMBER、$NUMBER1:$NUMBER2(数字范围)、$NUMBER:HEAD 和 BASE:$NUMBER 都受支持。

这允许您在运行 fetch 时创建部分镜像;但这通常不建议这样做,因为历史记录将被跳过并丢失。

-
--stdin

仅与set-tree命令一起使用。

从 stdin 读取提交列表,并以相反的顺序提交它们。每行只读取前导 sha1,因此可以使用git rev-list --pretty=oneline 输出。

--rmdir

仅与dcommitset-treecommit-diff 命令一起使用。

如果目录中没有剩余文件,则从 SVN 树中删除目录。SVN 可以对空目录进行版本控制,如果目录中没有剩余文件,则默认情况下不会删除它们。Git 不能对空目录进行版本控制。启用此标志将使对 SVN 的提交行为类似于 Git。

config key: svn.rmdir
-e
--edit

仅与dcommitset-treecommit-diff 命令一起使用。

在提交到 SVN 之前编辑提交消息。对于作为提交的对象,此选项默认关闭,并在提交树对象时强制打开。

config key: svn.edit
-l<num>
--find-copies-harder

仅与dcommitset-treecommit-diff 命令一起使用。

它们都被直接传递给git diff-tree;有关更多信息,请参阅git-diff-tree[1]

config key: svn.l
config key: svn.findcopiesharder
-A<filename>
--authors-file=<filename>

语法与git cvsimport使用的文件兼容,但可以使用<>提供空电子邮件地址。

	loginname = Joe User <[email protected]>

如果指定了此选项,并且git svn遇到作者文件中不存在的 SVN 提交者名称,则git svn将中止操作。然后,用户必须添加相应的条目。在修改作者文件后重新运行之前的git svn命令应该继续操作。

config key: svn.authorsfile
--authors-prog=<filename>

如果指定了此选项,对于作者文件中不存在的每个 SVN 提交者名称,都会使用提交者名称作为第一个参数执行给定的文件。程序应返回形如 "Name <email>" 或 "Name <>" 的单行,它将被视为包含在作者文件中。

由于历史原因,filename 的相对路径首先将在当前目录中针对initclone 进行搜索,并在工作树的根目录中针对fetch 进行搜索。如果未找到filename,则会像在$PATH中搜索其他命令一样进行搜索。

config key: svn.authorsProg
-q
--quiet

使git svn更不冗长。指定第二次以使其更不冗长。

-m
--merge
-s<strategy>
--strategy=<strategy>
-p
--rebase-merges

这些仅与dcommitrebase 命令一起使用。

如果不能使用git reset(请参阅dcommit),则在使用dcommit时直接传递给git rebase

-n
--dry-run

此选项可用于 dcommitrebasebranchtag 命令。

对于 dcommit,它会打印出一系列 Git 参数,这些参数将显示哪些差异将被提交到 SVN。

对于 rebase,它会显示与当前分支关联的上游 svn 存储库的本地分支,以及将从中获取的 svn 存储库的 URL。

对于 branchtag,它会显示在创建分支或标签时用于复制的 URL。

--use-log-author

在将 svn 提交检索到 Git 中时(作为 fetchrebasedcommit 操作的一部分),它会在日志消息中查找第一个 From: 行或 Signed-off-by 尾部,并将其用作作者字符串。

config key: svn.useLogAuthor
--add-author-from

在从 Git 提交到 svn 时(作为 set-treedcommit 操作的一部分),如果现有的日志消息中还没有 From:Signed-off-by 尾部,它会根据 Git 提交的作者字符串追加一个 From: 行。如果你使用这个选项,那么 --use-log-author 将为所有提交检索到一个有效的作者字符串。

config key: svn.addAuthorFrom

高级选项

-i<GIT_SVN_ID>
--id <GIT_SVN_ID>

这将设置 GIT_SVN_ID(而不是使用环境变量)。这允许用户覆盖在跟踪单个 URL 时从其获取的默认 refname。logdcommit 命令不再需要此选项作为参数。

-R<remote-name>
--svn-remote <remote-name>

指定要使用的 [svn-remote "<remote-name>"] 部分,这允许跟踪多个 SVN 存储库。默认值: "svn"

--follow-parent

此选项仅在跟踪分支时相关(使用存储库布局选项之一 --trunk、--tags、--branches、--stdlayout)。对于每个跟踪的分支,尝试找出其修订版是从何处复制的,并在分支的第一个 Git 提交中设置一个合适的父级。这在跟踪已在存储库中移动的目录时特别有用。如果禁用此功能,由 git svn 创建的分支将全部是线性的,并且不会共享任何历史记录,这意味着将没有关于分支在哪里分支或合并的信息。但是,跟踪长/复杂的历史记录可能需要很长时间,因此禁用此功能可以加快克隆过程。默认情况下,此功能处于启用状态,可以使用 --no-follow-parent 禁用它。

config key: svn.followparent

配置文件专用选项

svn.noMetadata
svn-remote.<name>.noMetadata

这会删除每个提交末尾的 git-svn-id: 行。

此选项只能用于一次性导入,因为 git svn 将无法在没有元数据的情况下再次获取。此外,如果你丢失了 $GIT_DIR/svn/**/.rev_map.* 文件,git svn 将无法重建它们。

git svn log 命令也不能在使用此选项的存储库上运行。使用此选项会与 useSvmProps 选项冲突,原因很明显。

此选项**不推荐**使用,因为它难以在现有的文档、错误报告和存档中跟踪对 SVN 修订版号的旧引用。如果你计划最终从 SVN 迁移到 Git,并且确定要放弃 SVN 历史记录,请考虑使用 git-filter-repo。filter-repo 还允许重新格式化元数据以方便阅读,并为非 "svn.authorsFile" 用户重写作者信息。

svn.useSvmProps
svn-remote.<name>.useSvmProps

这允许 git svn 从使用 SVN::Mirror(或 svk)创建的镜像重新映射存储库 URL 和 UUID 以用于元数据。

如果一个 SVN 修订版有一个属性 "svm:headrev",则该修订版很可能是由 SVN::Mirror(也由 SVK 使用)创建的。该属性包含一个存储库 UUID 和一个修订版。我们希望使其看起来像我们在镜像原始 URL,因此引入了一个辅助函数来返回原始身份 URL 和 UUID,并在生成提交消息中的元数据时使用它。

svn.useSvnsyncProps
svn-remote.<name>.useSvnsyncprops

类似于 useSvmProps 选项;这适用于 SVN 1.4.x 及更高版本中包含的 svnsync(1) 命令的用户。

svn-remote.<name>.rewriteRoot

这允许用户从备用 URL 创建存储库。例如,管理员可以在服务器本地运行 git svn(通过 file:// 访问),但希望使用公共 http:// 或 svn:// URL 在元数据中分发存储库,以便其用户看到公共 URL。

svn-remote.<name>.rewriteUUID

类似于 useSvmProps 选项;这适用于需要手动重新映射 UUID 的用户。这可能在原始 UUID 无法通过 useSvmProps 或 useSvnsyncProps 获得的情况下很有用。

svn-remote.<name>.pushurl

类似于 Git 的 remote.<name>.pushurl,此键旨在用于 url 通过只读传输指向 SVN 存储库的情况,以提供备用读/写传输。假设这两个键都指向同一个存储库。与 commiturl 不同,pushurl 是一个基本路径。如果可以使用 commiturlpushurl,则 commiturl 优先。

svn.brokenSymlinkWorkaround

这会禁用可能代价高昂的检查,以解决由损坏的客户端签入 SVN 的损坏符号链接。如果跟踪一个 SVN 存储库,该存储库中包含许多不是符号链接的空 Blob,则将此选项设置为 "false"。此选项可以在 git svn 运行时更改,并在下次获取修订版时生效。如果未设置,git svn 假设此选项为 "true"。

svn.pathnameencoding

这指示 git svn 将路径名重新编码为给定的编码。Windows 用户和在非 utf8 本地化中工作的人可以使用它来避免使用非 ASCII 字符的损坏文件名。有效的编码是 Perl 的 Encode 模块支持的编码。

svn-remote.<name>.automkdirs

通常,"git svn clone" 和 "git svn rebase" 命令尝试重新创建 Subversion 存储库中的空目录。如果将此选项设置为 "false",则只有在显式运行 "git svn mkdirs" 命令时才会创建空目录。如果未设置,git svn 假设此选项为 "true"。

由于 noMetadata、rewriteRoot、rewriteUUID、useSvnsyncProps 和 useSvmProps 选项都会影响 git svn 生成的和使用的元数据;因此,它们**必须**在导入任何历史记录之前在配置文件中设置,并且这些设置在设置后永远不应该更改。

此外,每个 svn-remote 部分只能使用这些选项中的一个,因为它们会影响 git-svn-id: 元数据行,除了 rewriteRoot 和 rewriteUUID 可以一起使用之外。

基本示例

跟踪和贡献到一个由 Subversion 管理的项目的 trunk(忽略标签和分支)

# Clone a repo (like git clone):
	git svn clone http://svn.example.com/project/trunk
# Enter the newly cloned directory:
	cd trunk
# You should be on master branch, double-check with 'git branch'
	git branch
# Do some work and commit locally to Git:
	git commit ...
# Something is committed to SVN, rebase your local changes against the
# latest changes in SVN:
	git svn rebase
# Now commit your changes (that were committed previously using Git) to SVN,
# as well as automatically updating your working HEAD:
	git svn dcommit
# Append svn:ignore and svn:global-ignores settings to the default Git exclude file:
	git svn show-ignore >> .git/info/exclude

跟踪和贡献到一个完整的由 Subversion 管理的项目(包括 trunk、标签和分支)

# Clone a repo with standard SVN directory layout (like git clone):
	git svn clone http://svn.example.com/project --stdlayout --prefix svn/
# Or, if the repo uses a non-standard directory layout:
	git svn clone http://svn.example.com/project -T tr -b branch -t tag --prefix svn/
# View all branches and tags you have cloned:
	git branch -r
# Create a new branch in SVN
	git svn branch waldo
# Reset your master to trunk (or any other branch, replacing 'trunk'
# with the appropriate name):
	git reset --hard svn/trunk
# You may only dcommit to one branch/tag/trunk at a time.  The usage
# of dcommit/rebase/show-ignore should be the same as above.

最初的 git svn clone 可能非常耗时(特别是对于大型 Subversion 存储库)。如果多个人(或一个在多台机器上工作的人)想要使用 git svn 来与同一个 Subversion 存储库交互,则可以将最初的 git svn clone 复制到服务器上的一个存储库中,然后让每个人使用 git clone 克隆该存储库

# Do the initial import on a server
	ssh server "cd /pub && git svn clone http://svn.example.com/project [options...]"
# Clone locally - make sure the refs/remotes/ space matches the server
	mkdir project
	cd project
	git init
	git remote add origin server:/pub/project
	git config --replace-all remote.origin.fetch '+refs/remotes/*:refs/remotes/*'
	git fetch
# Prevent fetch/pull from remote Git server in the future,
# we only want to use git svn for future updates
	git config --remove-section remote.origin
# Create a local branch from one of the branches just fetched
	git checkout -b master FETCH_HEAD
# Initialize 'git svn' locally (be sure to use the same URL and
# --stdlayout/-T/-b/-t/--prefix options as were used on server)
	git svn init http://svn.example.com/project [options...]
# Pull the latest changes from Subversion
	git svn rebase

REBASE 与 PULL/MERGE

建议使用 git svn rebasegit rebase,而不是 git pullgit merge 来将未合并的提交与 git svn 分支同步。这样做将使未合并提交的历史记录相对于上游 SVN 存储库保持线性,并允许使用首选的 git svn dcommit 子命令将未合并的提交推送到 SVN。

最初,git svn 建议开发人员从 git svn 分支中拉取或合并。这是因为作者更喜欢 git svn set-tree B 来提交单个头部,而不是 git svn set-tree A..B 符号来提交多个提交。将 git pullgit mergegit svn set-tree A..B 一起使用会导致在提交到 SVN 时将非线性历史记录扁平化,这会导致合并提交意外地反转 SVN 中的先前提交。

合并跟踪

虽然 git svn 可以跟踪采用标准布局的存储库的复制历史记录(包括分支和标签),但它还不能表示在 Git 内部发生的合并历史记录,而这些历史记录会传回到 SVN 用户。因此,建议用户在 Git 内部尽可能保持历史记录线性,以简化与 SVN 的兼容性(参见下面的注意事项部分)。

处理 SVN 分支

如果 git svn 配置为获取分支(并且 --follow-branches 生效),它有时会为一个 SVN 分支创建多个 Git 分支,其中附加的分支名称采用 branchname@nnn 的形式(其中 nnn 是一个 SVN 修订版号)。如果 git svn 无法找到 SVN 分支中第一个提交的父级提交,则会创建这些附加的分支,以将该分支连接到其他分支的历史记录。

通常,SVN 分支中的第一个提交包含一个复制操作。git svn 将读取此提交以获取创建该分支的 SVN 修订版。然后,它将尝试找到与该 SVN 修订版相对应的 Git 提交,并将其用作该分支的父级。但是,可能没有合适的 Git 提交可以作为父级。这种情况会在多种原因下发生,例如,如果 SVN 分支是尚未被 git svn 获取的修订版的副本(例如,因为它是一个使用 --revision 跳过的旧修订版),或者如果在 SVN 中复制了一个未被 git svn 跟踪的目录(例如,一个根本没有被跟踪的分支,或者被跟踪分支的子目录)。在这些情况下,git svn 仍然会创建一个 Git 分支,但它不会使用现有的 Git 提交作为该分支的父级,而是会读取复制该分支的目录的 SVN 历史记录,并创建相应的 Git 提交。这由消息 "Initializing parent: <branchname>" 指示。

此外,它还会创建一个名为 <branchname>@<SVN-Revision> 的特殊分支,其中 <SVN-Revision> 是复制该分支的 SVN 修订版号。此分支将指向新创建的分支的父级提交。如果在 SVN 中,该分支被删除,然后从另一个版本重新创建,那么将会有多个这样的分支,其中包含 @

请注意,这可能意味着单个 SVN 修订版会创建多个 Git 提交。

例如:在一个具有标准 trunk/tags/branches 布局的 SVN 存储库中,在 r.100 中创建了目录 trunk/sub。在 r.200 中,trunk/sub 通过将其复制到 branches/ 来分支。git svn clone -s 然后将创建一个分支 sub。它还将为 r.100 到 r.199 创建新的 Git 提交,并使用它们作为分支 sub 的历史记录。因此,从 r.100 到 r.199 的每个修订版将有两个 Git 提交(一个包含 trunk/,一个包含 trunk/sub/)。最后,它将创建一个分支 sub@200,指向分支 sub 的新父提交(即 r.200 和 trunk/sub/ 的提交)。

注意事项

为了简单起见,并与 Subversion 交互,建议所有 git svn 用户直接从 SVN 服务器克隆、获取和 dcommit,并避免 Git 存储库和分支之间的所有 git clone/pull/merge/push 操作。在 Git 分支和用户之间交换代码的推荐方法是 git format-patchgit am,或者只是将代码 'dcommit’ 到 SVN 存储库。

在计划从其 dcommit 的分支上运行 git mergegit pull **不推荐**,因为 Subversion 用户无法看到您所做的任何合并。此外,如果您从镜像 SVN 分支的 Git 分支进行合并或拉取,dcommit 可能提交到错误的分支。

如果您确实要合并,请注意以下规则:git svn dcommit 将尝试提交到名为

git log --grep=^git-svn-id: --first-parent -1

因此,您**必须**确保要 dcommit 到分支的最新提交是合并的**第一个**父提交。否则将导致混乱,特别是如果第一个父提交是同一 SVN 分支上的较旧提交。

git clone 不会克隆 refs/remotes/ 层级下的分支,也不会克隆任何 git svn 元数据或配置。因此,使用 git svn 创建和管理的存储库应使用 rsync 进行克隆(如果要进行克隆的话)。

由于 dcommit 在内部使用 rebase,因此您在 dcommit 之前 git push 到任何 Git 分支,都需要强制覆盖远程存储库上现有的 ref。这通常被认为是不好的做法,有关详细信息,请参阅 git-push[1] 文档。

不要在您已经 dcommit 的更改上使用 git-commit[1] 的 --amend 选项。在您已经推送到远程存储库供其他用户使用的提交上使用 --amend 被认为是不好的做法,而使用 SVN 进行 dcommit 类似于此。

克隆 SVN 存储库时,如果未使用任何描述存储库布局的选项(--trunk、--tags、--branches、--stdlayout),git svn clone 将创建一个具有完全线性历史记录的 Git 存储库,其中分支和标签在工作副本中显示为单独的目录。虽然这是获取完整存储库副本的最简单方法,但对于包含许多分支的项目来说,它会导致工作副本的大小是 trunk 的很多倍。因此,对于使用标准目录结构(trunk/branches/tags)的项目,建议使用 --stdlayout 选项进行克隆。如果项目使用非标准结构,或者如果不需要分支和标签,那么最简单的方法是只克隆一个目录(通常是 trunk),而不提供任何存储库布局选项。如果需要包含分支和标签的完整历史记录,则必须使用 --trunk / --branches / --tags 选项。

使用多个 --branches 或 --tags 时,git svn 不会自动处理名称冲突(例如,如果来自不同路径的两个分支具有相同的名称,或者如果分支和标签具有相同的名称)。在这种情况下,请使用 init 设置您的 Git 存储库,然后在第一次 fetch 之前,编辑 $GIT_DIR/config 文件,以便将分支和标签与不同的命名空间关联。例如

branches = stable/*:refs/remotes/svn/stable/*
branches = debug/*:refs/remotes/svn/debug/*

配置

git svn 将 [svn-remote] 配置信息存储在存储库的 $GIT_DIR/config 文件中。它类似于核心 Git [remote] 部分,只是 fetch 键不接受 glob 参数;而是由 branchestags 键处理。由于一些 SVN 存储库配置奇怪,具有多个项目 glob 扩展,因此允许如下所列的扩展

[svn-remote "project-a"]
	url = http://server.org/svn
	fetch = trunk/project-a:refs/remotes/project-a/trunk
	branches = branches/*/project-a:refs/remotes/project-a/branches/*
	branches = branches/release_*:refs/remotes/project-a/branches/release_*
	branches = branches/re*se:refs/remotes/project-a/branches/*
	tags = tags/*/project-a:refs/remotes/project-a/tags/*

请记住,本地 ref 的 *(星号)通配符(在 : 的右侧)**必须**是最右边的路径组件;但是,远程通配符可以在任何位置,只要它是独立的路径组件(被 / 或 EOL 包围)。这种类型的配置不会由 init 自动创建,应使用文本编辑器或 git config 手动输入。

另请注意,每个词语只允许一个星号。例如

branches = branches/re*se:refs/remotes/project-a/branches/*

将匹配分支 releaseresere123se,但是

branches = branches/re*s*e:refs/remotes/project-a/branches/*

将产生错误。

还可以通过在花括号中使用用逗号分隔的名称列表来获取分支或标签的子集。例如

[svn-remote "huge-project"]
	url = http://server.org/svn
	fetch = trunk/src:refs/remotes/trunk
	branches = branches/{red,green}/src:refs/remotes/project-a/branches/*
	tags = tags/{1.0,2.0}/src:refs/remotes/project-a/tags/*

支持多个 fetch、branches 和 tags 键

[svn-remote "messy-repo"]
	url = http://server.org/svn
	fetch = trunk/project-a:refs/remotes/project-a/trunk
	fetch = branches/demos/june-project-a-demo:refs/remotes/project-a/demos/june-demo
	branches = branches/server/*:refs/remotes/project-a/branches/*
	branches = branches/demos/2011/*:refs/remotes/project-a/2011-demos/*
	tags = tags/server/*:refs/remotes/project-a/tags/*

在这种配置中创建分支需要使用 -d 或 --destination 标志来消除歧义,以确定要使用哪个位置

$ git svn branch -d branches/server release-2-3-0

请注意,git-svn 会跟踪分支或标签出现的最高修订版。如果在获取后更改了分支或标签的子集,则必须手动编辑 $GIT_DIR/svn/.metadata 以删除(或重置)branches-maxRev 和/或 tags-maxRev,具体取决于情况。

文件

$GIT_DIR/svn/**/.rev_map.*

Subversion 修订版号和 Git 提交名称之间的映射。在未设置 noMetadata 选项的存储库中,可以从每个提交末尾的 git-svn-id: 行重新构建此映射(有关详细信息,请参阅上面的 svn.noMetadata 部分)。

git svn fetchgit svn rebase 会自动更新 rev_map(如果缺少或未更新)。git svn reset 会自动将其倒回。

错误

我们忽略所有 SVN 属性,除了 svn:executable。任何未处理的属性都会记录到 $GIT_DIR/svn/<refname>/unhandled.log 中

重命名和复制的目录不会被 Git 检测到,因此在提交到 SVN 时不会被跟踪。我不打算添加对此的支持,因为要为所有可能的极端情况(Git 也不会这样做)让它工作起来非常困难且耗时。如果重命名和复制的文件足够相似,以便 Git 可以检测到它们,则完全支持提交它们。

在 SVN 中,可以(尽管不建议)将更改提交到标签(因为标签只是一个目录副本,因此在技术上与分支相同)。克隆 SVN 存储库时,git svn 无法知道将来是否会发生对标签的这种提交。因此,它会保守地将所有 SVN 标签作为分支导入,并在标签名称前添加 tags/

参见

GIT

git[1] 套件的一部分

scroll-to-top