简体中文 ▾ 主题 ▾ 最新版本 ▾ 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 仓库,其中包含 git svn 的额外元数据目录。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 和 plain svn),请指定用户名。对于其他传输方式(例如 svn+ssh://),您必须在 URL 中包含用户名,例如 svn+ssh://foo@svn.bar.com/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 远程仓库中抓取未抓取的修订版本。$GIT_DIR/config 文件中 [svn-remote "…​"] 部分的名称可以作为可选命令行参数指定。

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

--localtime

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

这不会干扰与您克隆的 Subversion 仓库的互操作性,但如果您希望您的本地 Git 仓库能够与他人的本地 Git 仓库互操作,则要么不使用此选项,要么您都应该在相同的本地时区中使用它。

--parent

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

--ignore-refs=<regex>

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

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

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

--ignore-paths=<regex>

这允许您指定一个 Perl 正则表达式,该表达式将导致跳过从 SVN 检出所有匹配的路径。--ignore-paths 选项应该匹配给定仓库上的每次 fetch(包括由于 clonedcommitrebase 等引起的自动抓取)。

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 选项应该匹配给定仓库上的每次 fetch(包括由于 clonedcommitrebase 等引起的自动抓取)。--ignore-paths 优先于 --include-paths

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

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

clone

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

--preserve-empty-dirs

为从 Subversion 抓取的每个空目录在本地 Git 仓库中创建一个占位文件。这包括通过删除 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 和 head 之间是否存在差异)。这将在 SVN 中为 Git 中的每个提交创建一个修订版本。

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

优先使用 dcommit 而不是 set-tree(见下文)。

--no-rebase

提交后,不进行变基或重置。

--commit-url <URL>

提交到此 SVN URL(完整路径)。这旨在允许在用户稍后获得提交的替代传输方法(例如 svn+ssh://https://)访问时,可以重用使用一种传输方法(例如 svn://http:// 用于匿名读取)创建的现有 git svn 仓库。

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 提交任何内容。

branch

在 SVN 仓库中创建分支。

-m
--message

允许指定提交消息。

-t
--tag

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

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

如果向 initclone 命令提供了多个 --branches(或 --tags)选项,则必须提供您希望在 SVN 仓库中创建的分支(或标签)的位置。<path> 指定用于创建分支或标签的路径,并且应与已配置的分支或标签引用规范之一的左侧模式匹配。您可以使用以下命令查看这些引用规范

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

其中 <name> 是通过 init 命令的 -R 选项指定的 SVN 仓库名称(默认情况下为 "svn")。

--username

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

--commit-url

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

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

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

tag

在 SVN 仓库中创建标签。这是 branch -t 的简写。

log

这应该使 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

blame

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

--git-format

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

find-rev

当给定形式为 rN 的 SVN 修订版本号时,返回相应的 Git 提交哈希(这可以选择性地后跟一个 tree-ish 以指定应搜索哪个分支)。当给定一个 tree-ish 时,返回相应的 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

提交命令行中两个 tree-ish 参数的差异。此命令不依赖于在 git svn init 过的仓库中。此命令接受三个参数:(a) 要进行差异比较的原始树,(b) 新树结果,(c) 目标 Subversion 仓库的 URL。如果您正在从一个 git svn 感知的仓库(已用 git svn init 过的仓库)工作,则可以省略最后一个参数 (URL)。此命令需要 -r<revision> 选项。

提交消息可以直接通过 -m-F 选项提供,或者当第二个 tree-ish 指示此类对象时间接从标签或提交中获取,或者通过调用编辑器请求(参见下面的 --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 可能会因“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 树中删除目录。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 <user@example.com>

如果指定此选项,并且 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 命令一起使用。

当使用 dcommit 且无法使用 git reset 时(参见 dcommit),直接传递给 git rebase

-n
--dry-run

这可以与 dcommitrebasebranchtag 命令一起使用。

对于 dcommit,打印出将显示哪些差异将提交到 SVN 的 Git 参数序列。

对于 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 用户和在非 UTF-8 区域设置中工作的用户可以使用它,以避免带有非 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 管理的项目的主干并为其贡献(忽略标签和分支)

# 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 管理的项目(包含主干、标签和分支)

# 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 兼容(参见下面的 CAVEATS 部分)。

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 仓库中,目录 trunk/sub 在 r.100 中创建。在 r.200 中,通过将其复制到 branches/ 来创建 trunk/sub 分支。然后 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 分支都将需要强制覆盖远程仓库上现有引用。这通常被认为是坏习惯,有关详细信息,请参阅 git-push[1] 文档。

不要对您已经 dcommit 的更改使用 git-commit[1] 的 --amend 选项。修改您已经推送到远程仓库供其他用户使用的提交被认为是坏习惯,而 SVN 的 dcommit 与此类似。

克隆 SVN 仓库时,如果没有使用任何描述仓库布局的选项(--trunk、--tags、--branches、--stdlayout),git svn clone 将创建一个具有完全线性历史的 Git 仓库,其中分支和标签在工作副本中显示为单独的目录。虽然这是获取完整仓库副本最简单的方法,但对于具有许多分支的项目,它将导致工作副本比仅主干大许多倍。因此,对于使用标准目录结构(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/*

请记住,本地引用(: 右侧)的 *(星号)通配符必须是最右侧的路径组件;但远程通配符可以在任何位置,只要它是一个独立的路径组件(由 / 或行尾包围)。此类型的配置不会由 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 部分)。

如果 rev_map 缺失或未更新,git svn fetchgit svn rebase 会自动更新它。git svn reset 会自动回滚它。

BUG

我们忽略所有 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