Git
章 ▾ 第2版

9.2 Gitと他のシステム - Gitへの移行

Gitへの移行

既存のコードベースが別のVCSにあるが、Gitを使い始めることに決めた場合は、何らかの方法でプロジェクトを移行する必要があります。このセクションでは、一般的なシステム用のいくつかのインポーターについて説明し、独自のカスタムインポーターを開発する方法を示します。切り替えを行うユーザーの大部分を占め、高品質なツールが手に入りやすいため、専門的に使用されているいくつかの大規模なSCMシステムからデータをインポートする方法を学びます。

Subversion

git svnの使用に関する前のセクションを読んだ場合、その手順を簡単に使用してリポジトリをgit svn cloneできます。次に、Subversionサーバーの使用を停止し、新しいGitサーバーにプッシュして、それを使用し始めることができます。履歴が必要な場合は、Subversionサーバーからデータをプルするのにかかる時間で、それを行うことができます(時間がかかる場合があります)。

ただし、インポートは完璧ではありません。時間がかかるため、適切に行う方が良いでしょう。最初の問題は、作成者情報です。Subversionでは、コミットする各ユーザーは、コミット情報に記録されるシステム上のユーザーを持ちます。前のセクションの例では、blame出力やgit svn logなど、一部の場所にschaconが表示されています。これをより適切な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タグが取り除かれます。明らかに、これはgrepsort、およびperlがインストールされたマシンでのみ機能します。次に、その出力をusers.txtファイルにリダイレクトして、各エントリの横に同等のGitユーザーデータを追加できます。

注意

Windowsマシンでこれを試している場合、ここで問題が発生します。Microsoftは、https://learn.microsoft.com/en-us/azure/devops/repos/git/perform-migration-from-svn-to-gitでいくつかの良いアドバイスとサンプルを提供しています。

このファイルをgit svnに提供して、作成者データをより正確にマップすることができます。また、git svnに、通常Subversionがインポートするメタデータを含めないように指示することもできます。これには、cloneまたはinitコマンドに--no-metadataを渡します。メタデータには、インポート中にGitが生成する各コミットメッセージ内のgit-svn-idが含まれます。これにより、Gitログが肥大化し、少し不明瞭になる可能性があります。

注意

Gitリポジトリで行われたコミットを元のSVNリポジトリにミラーリングする場合は、メタデータを保持する必要があります。コミットログに同期が必要ない場合は、--no-metadataパラメーターを省略してください。

これにより、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

Authorフィールドの見栄えが良くなっただけでなく、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

Subversionでは1つのブランチしか表示されないのに、@xxx(xxxは数字)という接尾辞が付いた追加のブランチが表示される場合があります。これは実際にはSubversionの「ペグリビジョン」と呼ばれる機能で、Gitには構文上の対応物がありません。したがって、git svnは、SVNでそのブランチのペグリビジョンを指定する場合と同じように、SVNバージョン番号をブランチ名に追加します。ペグリビジョンについてもう気にしない場合は、それらを削除するだけで済みます。

$ for p in $(git for-each-ref --format='%(refname:short)' | grep @); do git branch -D $p; done

これで、すべての古いブランチが実際のGitブランチになり、すべての古いタグが実際のGitタグになります。

最後にクリーンアップすることがもう1つあります。残念ながら、git svnは、Subversionのデフォルトブランチにマップされるtrunkという名前の追加ブランチを作成しますが、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は、変更セットの作者フィールドに入れる内容についてGitよりも少し寛容であるため、整理する良い機会です。これを生成するには、bashシェルで1行のコマンドを実行します。

$ 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)が4つの異なる名前で変更セットを作成しており、そのうち1つは実際に正しく見え、1つは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>"

Mercurialの名前がGitで許可されていない場合、同じ種類のマッピングファイルを使用して、ブランチとタグの名前を変更できます。

次のステップは、新しいGitリポジトリを作成し、エクスポートスクリプトを実行することです。

$ git init /tmp/converted
$ cd /tmp/converted
$ /tmp/fast-export/hg-fast-export.sh -r /tmp/hg-repo -A /tmp/authors

-rフラグは、変換するMercurialリポジトリを見つける場所をhg-fast-exportに指示し、-Aフラグは、作者マッピングファイルを見つける場所を指示します(ブランチおよびタグマッピングファイルは、それぞれ-Bおよび-Tフラグで指定します)。スクリプトはMercurial変更セットを解析し、Gitの「高速インポート」機能(後で詳しく説明します)のスクリプトに変換します。これには少し時間がかかります(ただし、ネットワーク経由よりもはるかに高速です)。出力はかなり冗長です。

$ /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が相互に通信する方法は2つあります。git-p4とPerforce Git Fusionです。

Perforce Git Fusion

Git Fusionは、このプロセスを非常に簡単にします。構成ファイルを使用して、プロジェクト設定、ユーザーマッピング、およびブランチを構成するだけで(Git Fusionで説明)、リポジトリをクローンします。Git Fusionは、ネイティブのGitリポジトリのように見えるものを提供し、必要に応じてネイティブのGitホストにプッシュする準備ができています。必要であれば、PerforceをGitホストとして使用することもできます。

Git-p4

Git-p4はインポートツールとしても機能します。例として、PerforceパブリックデポからJamプロジェクトをインポートします。クライアントを設定するには、Perforceデポを指すようにP4PORT環境変数をエクスポートする必要があります。

$ 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%)

この特定のプロジェクトにはブランチが1つしかありませんが、ブランチビュー(または単にディレクトリのセット)で構成されたブランチがある場合は、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を使用する必要があります。このコマンドは、stdinから単純な命令を読み取って、特定のGitデータを書き込みます。生のGitコマンドを実行したり、生のオブジェクトを書き込もうとしたりするよりも、この方法でGitオブジェクトを作成する方がはるかに簡単です(詳細については、Gitの内部を参照してください)。この方法では、インポート元のシステムから必要な情報を読み取り、stdoutに簡単な命令を出力するインポートスクリプトを作成できます。次に、このプログラムを実行し、その出力を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にコンテンツのスナップショット、それを指すコミットデータ、およびそれらの順序を伝えることだけです。戦略は、スナップショットを1つずつ調べて、各ディレクトリのコンテンツを含むコミットを作成し、各コミットを前のコミットにリンクすることです。

Git適用ポリシーの例で行ったように、通常使用し、読みやすい傾向があるため、これはRubyで記述します。この例は、使い慣れたものであれば、何でも非常に簡単に記述できます。stdoutに適切な情報を出力するだけで済みます。また、Windowsで実行している場合は、行末にキャリッジリターンを導入しないように特別な注意を払う必要があります。git fast-importは、Windowsが使用するキャリッジリターンラインフィード(CRLF)ではなく、ラインフィード(LF)だけを非常に具体的に求めています。

まず、ターゲットディレクトリに移動し、各サブディレクトリを識別します。各サブディレクトリは、コミットとしてインポートするスナップショットです。各サブディレクトリに移動し、それをエクスポートするために必要なコマンドを出力します。基本的なメインループは次のようになります。

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を実行します。これは、前のスナップショットのマニフェストとマークを取得し、このスナップショットのマニフェストとマークを返します。これにより、それらを適切にリンクできます。「マーク」は、コミットに与える識別子の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のmanページで、この方法でデータを提供する方法の詳細を確認してください。

新しいファイルの内容をリストしたり、新しい内容で変更されたファイルを指定する形式は次のとおりです。

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を使用しますが、git fast-importはLFのみを期待します。この問題を回避し、git fast-importを正常に動作させるために、RubyにCRLFではなくLFを使用するように指示する必要があります。

$stdout.binmode

これで終わりです。スクリプト全体は次のとおりです。

#!/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
---------------------------------------------------------------------

ご覧のとおり、正常に完了すると、達成したことに関する多くの統計が表示されます。この場合、4つのコミットに対して合計13個のオブジェクトを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ディレクトリにあります。

scroll-to-top