StGIT は Python アプリケーションであり、機能的には quilt と同じような ことをします (例えば、スタックへの push や pop を行ないます)。 diffpatch の代わりに GIT を使用しているという点が異なります。 StGIT はパッチを GIT リポジトリ内に通常のGITコミットオブジェクトとして 格納します。 StGIT は GIT の上位の SCM インターフェースではありません。 標準的な SCM 操作については、GIT のコマンド又は Cogito ツールを 使用してください。 StGit は http://www.procode.org/stgit/ からダウンロードできます。 このチュートリアルは既に GIT を理解している人を対象にしています。 GIT の詳しい情報は GIT_tutorial 又は git(7) を参照してください。

基本操作

Help

StGIT コマンドの完全な一覧:

stg help

各サブコマンドのヘルプ:

stg <cmd> (-h | --help)

リポジトリの初期化

スタンドアロンで動かす場合、StGIT は ('git-init-db'を使用して) 既に 初期化された GIT リポジトリと結合して使用します。 StGIT は GIT リポジトリ無しには使用することはできません。 GIT リポジトリの任意のブランチを StGIT で管理することができます。 StGIT により管理される各ブランチは、独立した一連の StGIT のパッチを 含んでいます。 既存の GIT ブランチを StGIT の管理下にするには、 GIT リポジトリの最上位に移動し、StGIT により管理したいブランチをチェックアウト した後、次のようにします:

stg init

stg init コマンドは、既に存在し StGit で管理する予定の ブランチに対して実行してください。 次のようにして GIT のブランチ間を切り替えることができます:

stg branch [<branch name>]

これは指定した名前のブランチをチェックアウトし、 そのブランチ内に StGIT のパッチを適用した状態に移動します。 この代わりに、StGIT コマンドだけを使用してブランチを作成することもできます:

stg branch --create <new branch>

リモートリポジトリとの作業

1つのコマンドで StGIT は GIT リポジトリの作成と初期化をすることができます。 これは複製(cloning)として知られていて、GIT で利用可能な全てのプロトコルが サポートされています。 リポジトリを複製するには、次のようにします:

stg clone <repository> <local-dir>

これは、GIT データベースの入った新しいローカルリポジトリを作成し、 リモートの最新のバージョンを pull し、StGIT が使用する master ブランチを 初期化します。 何時でもリモートのリポジトリから最新の変更を pull することができます。 デフォルトでは、StGIT は .git/branches/origin 内に格納されている場所から pull し、現在のブランチのベースを更新します。 最新の変更をリモートのリポジトリから pull するには、次のようにします:

stg pull [<branch> or 'origin']

このコマンドは現在のブランチから適用済みの StGIT のパッチ全てを削除し、 ブランチのベースコミットを更新し、再度パッチの適用を試みます。 マージ時にコンフリクトが発生すると、このプロセスは終了し、 コンフリクトを解消した後に続行することができます(以下を参照)。 リモートリポジトリの管理者があなたのパッチを公開用リポジトリに 適用済みの場合は、StGIT は通常、リモートから来たパッチがあなたのパッチと 一致していることを認識し、ローカルのバージョンを空のパッチへと変更します。 pull した後に空になったパッチを自動的に削除するには、次のようにします:

stg clean

慣例として、master ブランチは参照専用として使用し、変更は加えないで ください。このブランチは他の人の作業を反映するためのものだからです。 自分の GIT リポジトリを公開する場合は、自身のブランチに分けてその作業を 記録し、他の人があなたのパッチだけを pull できるようにする方が 便利です。

はじめの一歩:パッチの作成

作業ディレクトリに加えた変更はパッチとして保存します。 StGit のパッチは作業ディレクトリの変更を保存した単純な集合と、 それに説明が加わったものです。空の StGIT パッチを現在のブランチに作成 するには次のようにします:

stg new <name>

変更を保存し(パッチを更新するには)、次のようにします:

stg refresh

作業ディレクトリ内の変更を消すには、次のようにします:

git checkout -f

これは、最後にパッチが更新されたときの状態に作業ディレクトリを 戻します。 保存されていない変更は、次のようにして確認できます:

stg status

既にパッチ内に保存した変更を参照するには、次のようにします:

stg files

stg refresh コマンドは自動的に作業ディレクトリ内で実施した ファイルの変更を記録します。ただし、ファイルの追加、削除、名前 変更がある場合は、明示的に StGIT に伝える必要があります。 ファイルの追加や削除を新しいパッチに記録するには次のようにします:

stg add [<file>*]
stg rm [<file>*]

ファイル名の変更を新しいパッチに記録するには、 これらのコマンドを両方実行します:

stg rm <oldfilename>
stg add <newfilename>

スタックの運用:複数のパッチを管理する

StGIT は1度に1つ以上のパッチを管理できます。 GIT ブランチ内の一連の StGIT のパッチは、集合的なスタックとして知られています 上記で作成した新しいパッチは、現在あなたのスタック内の最上位のパッチです。 (現在の)最上位のパッチの名前は次のようにして確認できます:

stg top

最上位のパッチはほとんどの StGIT 操作がデフォルトのパッチとして 使用します。例えば、stg refresh のデフォルトのターゲットとなります。 スタックに push されたパッチは適用され、 スタックから pop されたパッチは非適用になります。 パッチをスタックに push/pop するには次のようにします:

stg push [--all | <name>]
stg pop [--all]

push した最新のパッチは最上位のパッチとなります。このパッチは 常に適用済みリストに含まれます;StGIT はパッチを適用しない限りは、 そのパッチに対する操作をすることはできません。 スタック内のパッチの順番を表示するには、次のコマンドを使用します:

stg series
stg applied
stg unapplied

デフォルトでは、stg push コマンドは非適用リストの1つ目のパッチを 適用しますが、パッチの名前を指定することで任意の未適用のパッチを push することができます。これはスタック内のパッチの順番を変更する時に 役に立ちます。 push 操作をすることにより、コンフリクトが発生することがあります (特に、スタック内のパッチの順番を変更した場合に発生します)。 push によりコンフリクトが発生した場合は、コンフリクトを解消し、 stg resolved を実行する必要があります(以下参照)。 push 操作は stg push —undo により取り消すこともできます。 その他のスタックの基礎;パッチ名の変更:

stg rename <old-name> <new-name>

パッチを削除するには:

stg delete <name>

これは指定した名前のパッチを恒久的に破棄します。言い換えると、 パッチはもはや適用、非適用のリストに表示されなくなり、 再適用することはできなくなります。 スタックしているパッチを恒久的にGITリポジトリ内に入れたい場合が あるかもしれません。例えば、リポジトリを他の人に公開するような場合です。 そうするには、次のようにします:

stg commit

これは適用済みの全てのパッチを GIT リポジトリにマージし、スタックから 削除します。このコマンドは適用済みのパッチを恒久的に格納し、 もはや StGIT では管理しない場合にのみ使用してください。

StGITパッチ と テキストdiff の変換

冒頭で述べたように、StGIT は作業ツリーの変更を GIT コミットの形式で 格納します。この為、GIT で管理していないツリーに変更を適用したい場合や 他の誰かに e-mail などで変更を送る場合には、StGIT のパッチを GNU patch コマンドで適用できる通常のテキストの diff に 変換する必要があります。 stg diff コマンドは強力な方法で StGIT が管理しているパッチを テキスト形式の diff に変換することができます。 最上位のパッチの diff を表示するには次のようにします:

stg diff -r /

これは、refresh コマンドにより保存されていない作業ディレクトリの変更は 表示しないことに注意してください。最後に refresh した後に行なった 変更を参照するには、次のようにします:

stg diff -r /top

パッチの変更と作業ディレクトリ内の未保存の変更とを一体化した 差分を表示したい場合は、次のようにします:

stg diff -r /bottom

スタック内の任意のパッチの変更を参照する場合、次のようにします:

stg diff -r <patch>/

スタックにある現在のパッチの全ての変更を表示するには、次のようにします:

stg diff -r base

stg diff コマンドは他にも役に立つたくさんの機能をサポートしています。 このコマンドのヘルプは是非参照してください。 StGIT のパッチをパッチファイルに変換するには、次のようにします。

stg export [--range=[<patch1>[:<patch2>]]] [<dir-name>]

export コマンドには自動的にパッチの番号を付けるオプション(-n)や、 .diff の拡張子を付けるオプション(-d) があります。 "stg export" はパッチの置き場所が指定されていない場合、"patch-ブランチ名" のディレクトリをカレントディレクトリ内に作成し、パッチをそこに格納します。 パッチまたは一連のパッチを e-mail するには、次のようにします:

stg mail [--to=...] (--all | --range=[<patch1>[:<patch2>]] | <patch>)

"stg mail" はたくさんのオプションを持っています。詳しい情報は "stg mail -h" の出力を参照してください。 GNU diff のパッチファイルを新しい StGIT パッチとしてインポートする コマンドもあります。"stg import" は自動的にパッチファイルを読み込み パッチの記述を抽出します。次のようにします:

stg import [<file>]

これは、"patch -i <file>" した後に "stg new" を実行し、 "stg refresh -e" するのと同じです。 時々、パッチファイルがきれいに適用されない場合があります。 その場合、"stg import" は空の StGIT パッチを残すので、 "patch -i" を使用して手動でパッチファイルを適用し、好きなエディタで 変更してください。 GNU diff ファイルを最上位のパッチにマージするには、次のようにします:

stg fold [<file>]

このコマンドは —threeway オプションをサポートしており、 パッチを最上位のパッチの底に適用し、3方向マージを実行します。 (訳注:ごめんなさい、意味がよくわかりませんでした。原文も載せます。 This command supports a —threeway option which applies the patch onto the bottom of the topmost one and performs a three-way merge.)

発展した使い方

マージ時のコンフリクトの取り扱い

パッチをスタックに push するとき、パッチがきれいに適用できない場合 push は失敗します。これは通常、次のような場合に発生します。 ツリーの変更が重なっていて、未適用の他のパッチに依存している場合、 または、パッチが送られてきた内容では正しく上流にマージできない場合。 push 操作は最初のパッチをコンフリクト状態で停止します。 status コマンドはコンフリクトしたファイルに C マークを付けて 表示します。keeporig オプションが yes(デフォルト) に設定されている 場合、マージ対象のファイルの元の状態は、<file>.older の名前でツリーに 残され、コンフリクトの解析をする為に <file>.local と <file>.remote が 作成されます。 diff3 がマージツール(デフォルト)として指定された場合、 コンフリクトマーカーがコンフリクトしたファイルに同じように追加されます。 resolved コマンドはコンフリクトが解消したことを記録し、 作業ツリーから一時作成されたマージファイルを削除します。 その後、refresh コマンドを実行するとコンフリクト解消後の修正結果で StGIT パッチを更新します。

設定ファイル

StGIT は次のファイルから設定オプションを読み込みます: /etc/stgitrc, ~/.stgitrc そして、.git/stgitrc。 後のファイルが先に出てきたファイルの内容を上書きします。 ファイルが無いときは、システムのデフォルトが使用されます。 設定ファイルの例は、examples/ ディレクトリ内にあります。 多くのユーザは mail コマンドが使用する smtpserver オプションを 定義するだけで十分でしょう。 gitmergeonefile.py スクリプトは merger オプションによって特定した ツールを使用して個々のファイルを3方向マージします。 ユーザはよりスマートなツールを使用するよう指定ができます。

テンプレート

exportmail コマンドはパッチファイルまたは e-mail を生成する際に テンプレートを使用します。デフォルトのテンプレートは、 <prefix>/share/stgit/templates/ の下にインストールされていて、 これを追加オプションと組み合わせるれば、大抵のユーザは十分です。 テンプレートの形式は標準的な Python の文字列書式のルールを使用しています。 利用できる変数はコマンドのヘルプメッセージで確認できます。 mail コマンドはデフォルトのテンプレートがない場合に初期の e-mail を 送信することもできます。<prefix>/share/stgit/examples/firstmail.tmpl ファイルを例として使用することができます。 新しいパッチのデフォルトの説明は .git/patchdescr.tmpl ファイルで 定義することができます。signed-off-by 行のようなものを入れるのに 役に立ちます。

2つのパッチを1つにマージする

今のところ、これを直接行なうコマンドはありませんが、 マージすべき内容をパッチファイルにエクスポートし、stg fold コマンドを 生成された diff ファイルに対して実行します。 マージされたパッチがまだ適用されていない場合は、その操作は成功します。 マージしたパッチをスタックに push すると、パッチは空のパッチになり (StGIT はそのことをユーザに知らせます)、安全に削除することができます。

技術的な情報

StGIT パッチ理論の一部

パッチは2つのノード間の差分であると想定します。- これを bottom, top とします。 1つのノードは GIT の専門用語の commit の SHA1 ID あるいは tree の SHA1 ID です:

P - patch
N - node
P = diff(Nt, Nb)
Nb - bottom (start) node
Nt - top (end) node
Nf - first node (for log generation)

パッチのスタックの並び順について:

P1 = diff(N1, N0)
P2 = diff(N2, N1)
...
Ps = P1 + P2 + P3 + ... = diff(Nst, Nsb)
Ps  - the big patch of the whole stack
Nsb - bottom stack node (= N0)
Nst - top stack node (= Nn)

Applying (pushing) a patch on the stack (Nst can differ from Nb) is done by diff3 merging. The new patch becomes:

P' = diff(Nt', Nb')
Nb' = Nst
Nt' = diff3(Nst, Nb, Nt)

(note that the diff3 parameters order is: branch1, ancestor, branch2) The above operation allows easy patch re-ordering. Removing (popping) a patch from the stack is done by simply setting the Nst to Nb.

Layout of the .git directory

HEAD                  -> refs/heads/<something>
objects/
  ??/
  ...
refs/
  heads/
    master            - the master commit id
    ...
  tags/
    ...
  branches/
    ...
  patches/
    master/
      applied         - list of applied patches
      unapplied               - list of not-yet applied patches
      current         - name of the topmost patch
      patch1/
        bottom                - the bottom id of the patch
        top           - the top id of the patch
      description     - the patch description
      authname        - author's name
      authemail       - author's e-mail
      commname        - committer's name
      commemail       - committer's e-mail
      patch2/
        ...
      ...
    ...