-
A1. 附录 A: Git 在其他环境
- A1.1 图形界面
- A1.2 Visual Studio 中的 Git
- A1.3 Visual Studio Code 中的 Git
- A1.4 IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine 中的 Git
- A1.5 Sublime Text 中的 Git
- A1.6 Bash 中的 Git
- A1.7 Zsh 中的 Git
- A1.8 PowerShell 中的 Git
- A1.9 小结
-
A2. 附录 B: 在应用程序中嵌入 Git
-
A3. 附录 C: Git 命令
9.2 Git 与其他系统 - 迁移到 Git
迁移到 Git
如果您在另一个 VCS 中拥有现有代码库,但已决定开始使用 Git,则必须以某种方式迁移您的项目。本节将介绍一些常见系统的导入器,然后演示如何开发您自己的自定义导入器。您将学习如何从一些主要的专业 SCM 系统导入数据,因为它们构成了大多数正在切换的用户,而且它们的优质工具也易于获取。
Subversion
如果您阅读了前面关于使用 git svn
的章节,您可以轻松地使用这些说明来 git svn clone
一个仓库;然后,停止使用 Subversion 服务器,推送到新的 Git 服务器,并开始使用它。如果您想要历史记录,您可以像从 Subversion 服务器拉取数据一样快速地完成(这可能需要一段时间)。
然而,导入并不完美;而且由于需要很长时间,您最好把它做好。第一个问题是作者信息。在 Subversion 中,每个提交者在系统上都有一个用户,该用户记录在提交信息中。前面章节中的示例在某些地方显示 schacon
,例如 blame
输出和 git svn log
。如果您想将其映射到更好的 Git 作者数据,您需要一个从 Subversion 用户到 Git 作者的映射。创建一个名为 users.txt
的文件,其中包含如下格式的映射:
schacon = Scott Chacon <schacon@geemail.com>
selse = Someo Nelse <selse@geemail.com>
要获取 SVN 使用的作者姓名列表,您可以运行此命令:
$ svn log --xml --quiet | grep author | sort -u | \
perl -pe 's/.*>(.*?)<.*/$1 = /'
这会生成 XML 格式的日志输出,然后只保留包含作者信息的行,去除重复项,并剥离 XML 标签。显然,这只适用于安装了 grep
、sort
和 perl
的机器。然后,将该输出重定向到您的 users.txt
文件,这样您就可以在每个条目旁边添加等效的 Git 用户数据。
注意
|
如果您在 Windows 机器上尝试此操作,则会遇到麻烦。Microsoft 在 https://learn.microsoft.com/en-us/azure/devops/repos/git/perform-migration-from-svn-to-git 提供了很好的建议和示例。 |
您可以将此文件提供给 git svn
以帮助它更准确地映射作者数据。您还可以通过向 clone
或 init
命令传递 --no-metadata
来告诉 git svn
不包含 Subversion 通常导入的元数据。元数据在 Git 导入期间生成的每个提交消息中包含一个 git-svn-id
。这可能会使您的 Git 日志变得庞大,并可能使其有点不清晰。
注意
|
当您想将 Git 仓库中进行的提交镜像回原始 SVN 仓库时,您需要保留元数据。如果您不想在提交日志中进行同步,请随意省略 |
这将使您的 import
命令看起来像这样:
$ git svn clone http://my-project.googlecode.com/svn/ \
--authors-file=users.txt --no-metadata --prefix "" -s my_project
$ cd my_project
现在,您应该在 my_project
目录中有一个更好的 Subversion 导入。提交不再看起来像这样:
commit 37efa680e8473b615de980fa935944215428a35a
Author: schacon <schacon@4c93b258-373f-11de-be05-5f7a86268029>
Date: Sun May 3 00:12:22 2009 +0000
fixed install - go to trunk
git-svn-id: https://my-project.googlecode.com/svn/trunk@94 4c93b258-373f-11de-
be05-5f7a86268029
它们看起来像这样:
commit 03a8785f44c8ea5cdb0e8834b7c8e6c469be2ff2
Author: Scott Chacon <schacon@geemail.com>
Date: Sun May 3 00:12:22 2009 +0000
fixed install - go to trunk
不仅作者字段看起来好多了,而且 git-svn-id
也不再存在。
您还应该做一些导入后的清理工作。首先,您应该清理 git svn
设置的那些奇怪的引用。您将把标签移动成实际的标签而不是奇怪的远程分支,然后将其余分支移动到本地。
要将标签移动为正确的 Git 标签,请运行:
$ for t in $(git for-each-ref --format='%(refname:short)' refs/remotes/tags); do git tag ${t/tags\//} $t && git branch -D -r $t; done
这会将以 refs/remotes/tags/
开头的远程分支引用转换为真实的(轻量级)标签。
接下来,将 refs/remotes
下的其余引用移动为本地分支:
$ for b in $(git for-each-ref --format='%(refname:short)' refs/remotes); do git branch $b refs/remotes/$b && git branch -D -r $b; done
您可能会看到一些以 @xxx
(其中 xxx 是一个数字)为后缀的额外分支,而在 Subversion 中您只看到一个分支。这实际上是 Subversion 的一个特性,称为“peg-revisions”,Git 简单地没有对应的语法。因此,git svn
只是将 SVN 版本号添加到分支名称中,就像您在 SVN 中编写它来寻址该分支的 peg-revision 一样。如果您不再关心 peg-revisions,只需删除它们:
$ for p in $(git for-each-ref --format='%(refname:short)' | grep @); do git branch -D $p; done
现在,所有旧分支都是真实的 Git 分支,所有旧标签都是真实的 Git 标签。
还有最后一件事要清理。不幸的是,git svn
创建了一个名为 trunk
的额外分支,它映射到 Subversion 的默认分支,但 trunk
引用指向与 master
相同的位置。由于 master
更符合 Git 的习惯用法,以下是删除额外分支的方法:
$ git branch -d trunk
最后要做的是将您的新 Git 服务器添加为远程并推送到它。以下是将您的服务器添加为远程的示例:
$ git remote add origin git@my-git-server:myrepository.git
因为您希望所有分支和标签都上传,所以现在可以运行此命令:
$ git push origin --all
$ git push origin --tags
所有分支和标签都应该以良好、干净的导入方式存在于您的新 Git 服务器上。
Mercurial
由于 Mercurial 和 Git 在表示版本方面有相当相似的模型,并且 Git 更加灵活,因此使用名为 "hg-fast-export" 的工具将仓库从 Mercurial 转换为 Git 是相当简单的,您需要一份该工具的副本:
$ git clone https://github.com/frej/fast-export.git
转换的第一步是完整克隆您要转换的 Mercurial 仓库:
$ hg clone <remote repo URL> /tmp/hg-repo
下一步是创建一个作者映射文件。Mercurial 在变更集(changesets)的作者字段中允许的内容比 Git 更宽松,所以这是一个清理的好时机。在 bash
shell 中生成它只需要一行命令:
$ cd /tmp/hg-repo
$ hg log | grep user: | sort | uniq | sed 's/user: *//' > ../authors
这需要几秒钟,具体取决于您项目的历史记录长度,之后 /tmp/authors
文件将看起来像这样:
bob
bob@localhost
bob <bob@company.com>
bob jones <bob <AT> company <DOT> com>
Bob Jones <bob@company.com>
Joe Smith <joe@company.com>
在此示例中,同一个人(Bob)以四个不同的名称创建了变更集,其中一个实际上看起来是正确的,而另一个对于 Git 提交将完全无效。Hg-fast-export 允许我们通过将每行转换为规则来解决此问题:"<input>"="<output>"
,将一个 <input>
映射到一个 <output>
。在 <input>
和 <output>
字符串中,支持 Python string_escape
编码理解的所有转义序列。如果作者映射文件不包含匹配的 <input>
,则该作者将未经修改地发送到 Git。如果所有用户名都看起来正常,我们根本不需要此文件。在此示例中,我们希望文件看起来像这样:
"bob"="Bob Jones <bob@company.com>"
"bob@localhost"="Bob Jones <bob@company.com>"
"bob <bob@company.com>"="Bob Jones <bob@company.com>"
"bob jones <bob <AT> company <DOT> com>"="Bob Jones <bob@company.com>"
当 Git 不允许 Mercurial 名称时,可以使用相同类型的映射文件来重命名分支和标签。
下一步是创建我们的新 Git 仓库,并运行导出脚本:
$ git init /tmp/converted
$ cd /tmp/converted
$ /tmp/fast-export/hg-fast-export.sh -r /tmp/hg-repo -A /tmp/authors
-r
标志告诉 hg-fast-export 在哪里找到我们要转换的 Mercurial 仓库,-A
标志告诉它在哪里找到作者映射文件(分支和标签映射文件分别由 -B
和 -T
标志指定)。该脚本解析 Mercurial 变更集并将其转换为 Git "fast-import" 功能的脚本(我们稍后会详细讨论)。这需要一些时间(尽管它比通过网络快得多),并且输出相当详细:
$ /tmp/fast-export/hg-fast-export.sh -r /tmp/hg-repo -A /tmp/authors
Loaded 4 authors
master: Exporting full revision 1/22208 with 13/0/0 added/changed/removed files
master: Exporting simple delta revision 2/22208 with 1/1/0 added/changed/removed files
master: Exporting simple delta revision 3/22208 with 0/1/0 added/changed/removed files
[…]
master: Exporting simple delta revision 22206/22208 with 0/4/0 added/changed/removed files
master: Exporting simple delta revision 22207/22208 with 0/2/0 added/changed/removed files
master: Exporting thorough delta revision 22208/22208 with 3/213/0 added/changed/removed files
Exporting tag [0.4c] at [hg r9] [git :10]
Exporting tag [0.4d] at [hg r16] [git :17]
[…]
Exporting tag [3.1-rc] at [hg r21926] [git :21927]
Exporting tag [3.1] at [hg r21973] [git :21974]
Issued 22315 commands
git-fast-import statistics:
---------------------------------------------------------------------
Alloc'd objects: 120000
Total objects: 115032 ( 208171 duplicates )
blobs : 40504 ( 205320 duplicates 26117 deltas of 39602 attempts)
trees : 52320 ( 2851 duplicates 47467 deltas of 47599 attempts)
commits: 22208 ( 0 duplicates 0 deltas of 0 attempts)
tags : 0 ( 0 duplicates 0 deltas of 0 attempts)
Total branches: 109 ( 2 loads )
marks: 1048576 ( 22208 unique )
atoms: 1952
Memory total: 7860 KiB
pools: 2235 KiB
objects: 5625 KiB
---------------------------------------------------------------------
pack_report: getpagesize() = 4096
pack_report: core.packedGitWindowSize = 1073741824
pack_report: core.packedGitLimit = 8589934592
pack_report: pack_used_ctr = 90430
pack_report: pack_mmap_calls = 46771
pack_report: pack_open_windows = 1 / 1
pack_report: pack_mapped = 340852700 / 340852700
---------------------------------------------------------------------
$ git shortlog -sn
369 Bob Jones
365 Joe Smith
差不多就是这样了。所有 Mercurial 标签都已转换为 Git 标签,Mercurial 分支和书签也已转换为 Git 分支。现在,您可以将仓库推送到其新的服务器端位置:
$ git remote add origin git@my-git-server:myrepository.git
$ git push origin --all
Perforce
接下来要查看的导入系统是 Perforce。正如我们上面讨论的,有两种方法可以让 Git 和 Perforce 相互通信:git-p4 和 Perforce Git Fusion。
Perforce Git Fusion
Git Fusion 使此过程相当轻松。只需使用配置文件(如 Git Fusion 中所讨论的)配置您的项目设置、用户映射和分支,然后克隆仓库。Git Fusion 会为您留下一个看起来像原生 Git 仓库的东西,如果您愿意,可以随时将其推送到原生 Git 主机。如果您喜欢,甚至可以使用 Perforce 作为您的 Git 主机。
Git-p4
Git-p4 也可以作为导入工具。例如,我们将从 Perforce 公共仓库导入 Jam 项目。要设置您的客户端,您必须导出 P4PORT 环境变量以指向 Perforce 仓库:
$ export P4PORT=public.perforce.com:1666
注意
|
为了继续操作,您需要一个 Perforce 仓库来连接。我们的示例将使用 public.perforce.com 上的公共仓库,但您可以使用您有权访问的任何仓库。 |
运行 git p4 clone
命令,从 Perforce 服务器导入 Jam 项目,提供仓库和项目路径以及您要导入项目的路径:
$ git-p4 clone //guest/perforce_software/jam@all p4import
Importing from //guest/perforce_software/jam@all into p4import
Initialized empty Git repository in /private/tmp/p4import/.git/
Import destination: refs/remotes/p4/master
Importing revision 9957 (100%)
这个特定项目只有一个分支,但如果您有配置了分支视图(或仅仅是一组目录)的分支,您可以使用 git p4 clone
的 --detect-branches
标志来导入项目的所有分支。有关更多详细信息,请参阅 分支。
此时您几乎完成了。如果您进入 p4import
目录并运行 git log
,您可以看到您导入的工作:
$ git log -2
commit e5da1c909e5db3036475419f6379f2c73710c4e6
Author: giles <giles@giles@perforce.com>
Date: Wed Feb 8 03:13:27 2012 -0800
Correction to line 355; change </UL> to </OL>.
[git-p4: depot-paths = "//public/jam/src/": change = 8068]
commit aa21359a0a135dda85c50a7f7cf249e4f7b8fd98
Author: kwirth <kwirth@perforce.com>
Date: Tue Jul 7 01:35:51 2009 -0800
Fix spelling error on Jam doc page (cummulative -> cumulative).
[git-p4: depot-paths = "//public/jam/src/": change = 7304]
您可以看到 git-p4
在每个提交消息中都留下了一个标识符。保留该标识符是可以的,以防您以后需要引用 Perforce 变更号。但是,如果您想删除该标识符,那么现在就是时候了——在您开始在新仓库上工作之前。您可以使用 git filter-branch
大量删除标识符字符串:
$ git filter-branch --msg-filter 'sed -e "/^\[git-p4:/d"'
Rewrite e5da1c909e5db3036475419f6379f2c73710c4e6 (125/125)
Ref 'refs/heads/master' was rewritten
如果您运行 git log
,您可以看到所有提交的 SHA-1 校验和都已更改,但 git-p4
字符串不再出现在提交消息中:
$ git log -2
commit b17341801ed838d97f7800a54a6f9b95750839b7
Author: giles <giles@giles@perforce.com>
Date: Wed Feb 8 03:13:27 2012 -0800
Correction to line 355; change </UL> to </OL>.
commit 3e68c2e26cd89cb983eb52c024ecdfba1d6b3fff
Author: kwirth <kwirth@perforce.com>
Date: Tue Jul 7 01:35:51 2009 -0800
Fix spelling error on Jam doc page (cummulative -> cumulative).
您的导入已准备好推送到您的新 Git 服务器。
自定义导入器
如果您的系统不是上述系统之一,您应该在线查找导入器——许多其他系统都有高质量的导入器,包括 CVS、Clear Case、Visual Source Safe,甚至是一个存档目录。如果这些工具都不适合您,或者您有一个更不常见的工具,或者您需要更自定义的导入过程,您应该使用 git fast-import
。此命令从标准输入读取简单指令以写入特定的 Git 数据。通过这种方式创建 Git 对象比运行原始 Git 命令或尝试写入原始对象(有关更多信息,请参阅 Git 内部原理)容易得多。这样,您可以编写一个导入脚本,从您要导入的系统中读取必要的信息,并向标准输出打印简单明了的指令。然后,您可以运行此程序并将其输出通过管道传递给 git fast-import
。
为了快速演示,您将编写一个简单的导入器。假设您在 current
中工作,您通过偶尔将目录复制到带时间戳的 back_YYYY_MM_DD
备份目录来备份您的项目,并且您希望将其导入到 Git 中。您的目录结构看起来像这样:
$ ls /opt/import_from
back_2014_01_02
back_2014_01_04
back_2014_01_14
back_2014_02_03
current
为了导入 Git 目录,您需要回顾 Git 如何存储其数据。正如您可能记得的,Git 本质上是一个提交对象的链表,这些对象指向内容的快照。您所要做的就是告诉 fast-import
内容快照是什么,哪些提交数据指向它们,以及它们的顺序。您的策略是逐个遍历快照,并使用每个目录的内容创建提交,将每个提交链接回前一个提交。
正如我们在 Git 强制策略示例 中所做的那样,我们将使用 Ruby 编写此内容,因为这是我们通常使用的语言,并且它易于阅读。您可以非常轻松地用您熟悉的任何语言编写此示例——它只需要将适当的信息打印到 stdout
。而且,如果您在 Windows 上运行,这意味着您需要特别注意不要在行尾引入回车符——git fast-import
对只要求换行符 (LF) 而不是 Windows 使用的回车换行符 (CRLF) 非常严格。
首先,您将进入目标目录并识别每个子目录,每个子目录都是您想要作为提交导入的快照。您将进入每个子目录并打印导出它所需的命令。您的基本主循环看起来像这样:
last_mark = nil
# loop through the directories
Dir.chdir(ARGV[0]) do
Dir.glob("*").each do |dir|
next if File.file?(dir)
# move into the target directory
Dir.chdir(dir) do
last_mark = print_export(dir, last_mark)
end
end
end
您在每个目录中运行 print_export
,它接受前一个快照的清单和标记,并返回当前快照的清单和标记;这样,您就可以正确地链接它们。“标记”(Mark)是 fast-import
中用来标识提交的术语;在创建提交时,您会给每个提交一个标记,您可以使用该标记从其他提交链接到它。因此,您在 print_export
方法中要做的第一件事是根据目录名称生成一个标记:
mark = convert_dir_to_mark(dir)
您将通过创建一个目录数组并使用索引值作为标记来完成此操作,因为标记必须是整数。您的方法看起来像这样:
$marks = []
def convert_dir_to_mark(dir)
if !$marks.include?(dir)
$marks << dir
end
($marks.index(dir) + 1).to_s
end
现在您有了提交的整数表示,您需要提交元数据的日期。由于日期是在目录名称中表达的,您将解析它。您的 print_export
文件中的下一行是:
date = convert_dir_to_date(dir)
其中 convert_dir_to_date
定义为:
def convert_dir_to_date(dir)
if dir == 'current'
return Time.now().to_i
else
dir = dir.gsub('back_', '')
(year, month, day) = dir.split('_')
return Time.local(year, month, day).to_i
end
end
这会返回每个目录日期的整数值。您为每个提交所需的最后一条元信息是提交者数据,您将其硬编码在全局变量中:
$author = 'John Doe <john@example.com>'
现在您已准备好开始为您的导入器打印提交数据。初始信息声明您正在定义一个提交对象及其所在的分支,然后是您生成的标记、提交者信息和提交消息,然后是前一个提交(如果有的话)。代码看起来像这样:
# print the import information
puts 'commit refs/heads/master'
puts 'mark :' + mark
puts "committer #{$author} #{date} -0700"
export_data('imported from ' + dir)
puts 'from :' + last_mark if last_mark
您硬编码时区 (-0700) 是因为这样做很简单。如果您从另一个系统导入,则必须将时区指定为偏移量。提交消息必须以特殊格式表达:
data (size)\n(contents)
格式由单词 data、要读取的数据大小、一个换行符以及最后的数据组成。由于您以后需要使用相同的格式来指定文件内容,因此您创建了一个辅助方法 export_data
:
def export_data(string)
print "data #{string.size}\n#{string}"
end
剩下要做的就是为每个快照指定文件内容。这很简单,因为您将每个快照都放在一个目录中——您可以打印 deleteall
命令,然后是目录中每个文件的内容。然后 Git 将适当地记录每个快照:
puts 'deleteall'
Dir.glob("**/*").each do |file|
next if !File.file?(file)
inline_data(file)
end
注意:由于许多系统将其版本视为从一个提交到另一个提交的更改,因此 fast-import 也可以在每个提交中使用命令来指定哪些文件已添加、删除或修改以及新的内容是什么。您可以计算快照之间的差异并仅提供这些数据,但这样做更复杂——您不妨将所有数据提供给 Git,让它自己计算出来。如果这更适合您的数据,请查阅 fast-import
手册页,了解如何以这种方式提供数据的详细信息。
列出新文件内容或指定包含新内容的修改文件的格式如下:
M 644 inline path/to/file
data (size)
(file contents)
这里,644 是模式(如果您有可执行文件,则需要检测并指定 755),inline 表示您将在此行之后立即列出内容。您的 inline_data
方法看起来像这样:
def inline_data(file, code = 'M', mode = '644')
content = File.read(file)
puts "#{code} #{mode} inline #{file}"
export_data(content)
end
您重用了之前定义的 export_data
方法,因为它与您指定提交消息数据的方式相同。
您需要做的最后一件事是返回当前标记,以便将其传递给下一次迭代:
return mark
注意
|
如果您在 Windows 上运行,您需要确保添加一个额外的步骤。如前所述,Windows 使用 CRLF 作为换行符,而
|
就这样。以下是完整的脚本:
#!/usr/bin/env ruby
$stdout.binmode
$author = "John Doe <john@example.com>"
$marks = []
def convert_dir_to_mark(dir)
if !$marks.include?(dir)
$marks << dir
end
($marks.index(dir)+1).to_s
end
def convert_dir_to_date(dir)
if dir == 'current'
return Time.now().to_i
else
dir = dir.gsub('back_', '')
(year, month, day) = dir.split('_')
return Time.local(year, month, day).to_i
end
end
def export_data(string)
print "data #{string.size}\n#{string}"
end
def inline_data(file, code='M', mode='644')
content = File.read(file)
puts "#{code} #{mode} inline #{file}"
export_data(content)
end
def print_export(dir, last_mark)
date = convert_dir_to_date(dir)
mark = convert_dir_to_mark(dir)
puts 'commit refs/heads/master'
puts "mark :#{mark}"
puts "committer #{$author} #{date} -0700"
export_data("imported from #{dir}")
puts "from :#{last_mark}" if last_mark
puts 'deleteall'
Dir.glob("**/*").each do |file|
next if !File.file?(file)
inline_data(file)
end
mark
end
# Loop through the directories
last_mark = nil
Dir.chdir(ARGV[0]) do
Dir.glob("*").each do |dir|
next if File.file?(dir)
# move into the target directory
Dir.chdir(dir) do
last_mark = print_export(dir, last_mark)
end
end
end
如果您运行此脚本,您将得到类似这样的内容:
$ ruby import.rb /opt/import_from
commit refs/heads/master
mark :1
committer John Doe <john@example.com> 1388649600 -0700
data 29
imported from back_2014_01_02deleteall
M 644 inline README.md
data 28
# Hello
This is my readme.
commit refs/heads/master
mark :2
committer John Doe <john@example.com> 1388822400 -0700
data 29
imported from back_2014_01_04from :1
deleteall
M 644 inline main.rb
data 34
#!/bin/env ruby
puts "Hey there"
M 644 inline README.md
(...)
要运行导入器,请在您要导入到的 Git 目录中,通过管道将此输出传递给 git fast-import
。您可以创建一个新目录,然后在其中运行 git init
作为起点,然后运行您的脚本:
$ git init
Initialized empty Git repository in /opt/import_to/.git/
$ ruby import.rb /opt/import_from | git fast-import
git-fast-import statistics:
---------------------------------------------------------------------
Alloc'd objects: 5000
Total objects: 13 ( 6 duplicates )
blobs : 5 ( 4 duplicates 3 deltas of 5 attempts)
trees : 4 ( 1 duplicates 0 deltas of 4 attempts)
commits: 4 ( 1 duplicates 0 deltas of 0 attempts)
tags : 0 ( 0 duplicates 0 deltas of 0 attempts)
Total branches: 1 ( 1 loads )
marks: 1024 ( 5 unique )
atoms: 2
Memory total: 2344 KiB
pools: 2110 KiB
objects: 234 KiB
---------------------------------------------------------------------
pack_report: getpagesize() = 4096
pack_report: core.packedGitWindowSize = 1073741824
pack_report: core.packedGitLimit = 8589934592
pack_report: pack_used_ctr = 10
pack_report: pack_mmap_calls = 5
pack_report: pack_open_windows = 2 / 2
pack_report: pack_mapped = 1457 / 1457
---------------------------------------------------------------------
如您所见,当它成功完成时,它会为您提供有关其所完成工作的许多统计信息。在这种情况下,您总共导入了 13 个对象,对应 4 个提交,并导入到 1 个分支中。现在,您可以运行 git log
查看您的新历史记录:
$ git log -2
commit 3caa046d4aac682a55867132ccdfbe0d3fdee498
Author: John Doe <john@example.com>
Date: Tue Jul 29 19:39:04 2014 -0700
imported from current
commit 4afc2b945d0d3c8cd00556fbe2e8224569dc9def
Author: John Doe <john@example.com>
Date: Mon Feb 3 01:00:00 2014 -0700
imported from back_2014_02_03
好了——一个漂亮、干净的 Git 仓库。需要注意的是,没有任何文件被检出——一开始您的工作目录中没有任何文件。要获取它们,您必须将分支重置到 master
当前所在的位置:
$ ls
$ git reset --hard master
HEAD is now at 3caa046 imported from current
$ ls
README.md main.rb
您可以使用 fast-import
工具做更多事情——处理不同的模式、二进制数据、多个分支和合并、标签、进度指示器等等。Git 源代码的 contrib/fast-import
目录中提供了许多更复杂场景的示例。