Gitで複数の作業ディレクトリを作成するにはどうすればいいですか? 質問する

Gitで複数の作業ディレクトリを作成するにはどうすればいいですか? 質問する

これが Git でサポートされているかどうかはわかりませんが、理論的には動作するはずです。

私のワークフローでは、複数のブランチにあるファイルを同時に編集することがよくあります。つまり、あるブランチにあるいくつかのファイルを開きながら、別のブランチにある別のファイルの内容を編集したいことがよくあります。

これに対する私の典型的な解決策は、チェックアウトを 2 つ作成することですが、それらの間でブランチと参照を共有できないのは残念です。私が望むのは、同じ.gitフォルダーで管理される 2 つの作業ディレクトリを持つことです。

git cloneローカルソリューション (共有オブジェクトをハードリンクするデフォルトと、元のリポジトリを使用して代替オブジェクト ストアを設定するオプション)があることは承知しています--sharedが、これらのソリューションではディスク領域の使用量が削減されるだけであり、特に の場合は--shared危険を伴うようです。

1 つのフォルダーを使用して、そのフォルダーに 2 つの作業ディレクトリをバックアップする方法はありますか.git? または、Git は、常に 1 つの作業ディレクトリのみがチェックアウトされるようにハードコードされていますか?

ベストアンサー1

Git 2.5 では、2015 年 7 月から次の代替案が提案されていますcontrib/workdir/git-new-workdirgit ワークツリー

見るコミット 68a2e6aによる浜野ジュニオ(gitster

リリースノートの記載:

これに代わるものはcontrib/workdir/git-new-workdir、シンボリック リンクに依存せず、借用者と借用者がお互いを認識することで、オブジェクトと参照の共有をより安全にします。

見るコミット 799767cc9(Git 2.5rc2)

つまり、あなたは今行うgit worktree add <path> [<branch>]

作成し<path>てチェックアウトします<branch>。新しい作業ディレクトリは現在のリポジトリにリンクされ、HEAD、インデックスなどの作業ディレクトリ固有のファイルを除くすべてのものを共有します。git worktreeセクションに追加:

Git リポジトリは複数の作業ツリーをサポートできるため、一度に複数のブランチをチェックアウトできます。
を使用するとgit worktree add、新しい作業ツリーがリポジトリに関連付けられます。

git initこの新しい作業ツリーは、「 」または「git clone」によって準備された「メイン作業ツリー」とは対照的に、「リンクされた作業ツリー」と呼ばれます
リポジトリには、1 つのメイン作業ツリー (ベア リポジトリでない場合) と 0 個以上のリンクされた作業ツリーがあります。

詳細:

リンクされた各作業ツリーには、リポジトリのディレクトリ内にプライベート サブディレクトリがあります$GIT_DIR/worktrees
プライベート サブディレクトリの名前は通常、リンクされた作業ツリーのパスのベース名であり、一意になるように番号が付加される場合があります。
たとえば、$GIT_DIR=/path/main/.gitコマンドが次git worktree add /path/other/test-next nextを作成すると:

  • リンクされた作業ツリー/path/other/test-next
  • ディレクトリも作成します$GIT_DIR/worktrees/test-next(または、すでに使用されている$GIT_DIR/worktrees/test-next1場合test-next)。

リンクされた作業ツリー内:

  • $GIT_DIRこのプライベートディレクトリを指すように設定されており(/path/main/.git/worktrees/test-next例)、
  • $GIT_COMMON_DIRメインの作業ツリーを指すように設定されます$GIT_DIR(例/path/main/.git)。

.gitこれらの設定は、リンクされた作業ツリーの最上位ディレクトリにあるファイルで行われます。

リンクされた作業ツリーの使用が終わったら、それを削除することができます。
リポジトリ内の作業ツリーの管理ファイルは、最終的には自動的に削除されます (gc.pruneworktreesexpireを参照git config)。または、メインまたはリンクされた作業ツリーで を実行して、古くなった管理ファイルをクリーンアップすることもできますgit worktree prune


警告: まだgit worktree「バグ」注意すべきセクション。

サポートサブモジュール不完全です
スーパープロジェクトを複数回チェックアウトすることは推奨されません。


注: git 2.7rc1 (2015年11月) では、ワークツリーを一覧表示できます。
コミット bb9c03bコミット 92718b7コミット 5193490コミット 1ceb7f9コミット 1ceb7f9コミット 5193490コミット 1ceb7f9コミット 1ceb7f9(2015年10月8日)コミット 92718b7コミット 5193490コミット 1ceb7f9コミット 1ceb7f9(2015年10月8日)コミット 5193490コミット 1ceb7f9(2015年10月8日)コミット 1ceb7f9(2015年10月8日)コミット ac6c561(2015年10月2日)マイケル・ラパッゾ ( rappazzo)(合併者
ジュニオ・C・ハマノ -- gitster--コミット a46dcfb、2015年10月26日)

worktree: ' list' コマンドを追加

' git worktree list' はワークツリー リストを反復処理し、ワークツリーへのパス、現在チェックアウトされているリビジョンとブランチ、ワークツリーがベアであるかどうかなど、ワークツリーの詳細を出力します。

$ git worktree list /path/to/bare-source (ベア) /path/to/linked-worktree abcd1234 [master] /path/to/other-linked-worktree 1234abc (分離された HEAD)

磁器形式のオプションもご利用いただけます。

磁器形式には、属性ごとに 1 行あります。

  • 属性は、ラベルと値が 1 つのスペースで区切られてリストされます。
  • ブール属性 (「bare」や「detached」など) はラベルとしてのみリストされ、値が true の場合にのみ存在します。
  • 空行はワークツリーの終わりを示します

例えば:

$ git worktree list --porcelain

worktree /path/to/bare-source
bare

worktree /path/to/linked-worktree
HEAD abcd1234abcd1234abcd1234abcd1234abcd1234
branch refs/heads/master

worktree /path/to/other-linked-worktree
HEAD 1234abc1234abc1234abc1234abc1234abc1234a
detached

注意: ワークツリー フォルダーを移動する場合は、ファイルを手動で更新する必要がありますgitdir

見るコミット 618244e(2016年1月22日)コミット d4cddd6(2016年1月18日)グエン・タイ・ゴック・デュイ ( pclouds).
協力者:エリック・サンシャイン(sunshineco(合併者
ジュニオ・C・ハマノ -- gitster--コミット d0a1cbc、2016年2月10日)

新しいドキュメントgit 2.8 (2016 年 3 月) には以下が含まれます:

gitdirリンクされた作業ツリーを移動する場合は、エントリのディレクトリにある' ' ファイルを更新する必要があります。
たとえば、リンクされた作業ツリーが に移動され/newpath/test-next、その.gitファイルが を指している場合は/path/main/.git/worktrees/test-next、代わりに/path/main/.git/worktrees/test-next/gitdirを参照するように更新します/newpath/test-next


ブランチを削除するときは注意してください。git 2.9 (2016 年 6 月) より前では、別の作業ツリーで使用中のブランチを削除することができました。

git worktree「 」機能が使用されている場合、「 git branch -d」は別のワークツリーでチェックアウトされているブランチの削除を許可します。

見るコミット f292244(2016年3月29日)山口和樹(rhenium.
協力者:エリック・サンシャイン(sunshineco(合併者
ジュニオ・C・ハマノ -- gitster--コミット 4fca4e3、2016年4月13日)

branch -d: 現在チェックアウトされているブランチの削除を拒否します

ブランチが現在の作業ツリーによってチェックアウトされている場合、ブランチの削除は禁止されています。
ただし、ブランチが他の作業ツリーによってのみチェックアウトされている場合、削除は誤って成功します。現在の作業ツリーの HEAD との比較だけでなく、ブランチが使用中かどうかを確認するために
使用します。find_shared_symref()


同様に、git 2.9 (2016 年 6 月) より前では、別のワークツリーでチェックアウトされたブランチの名前を変更しても、その他のワークツリーのシンボリック HEAD は調整されませんでした。

見るコミット 18eb3a9(2016年4月8日)コミット 70999e9コミット 2233066(2016年3月27日)山口和樹(rhenium(合併者
ジュニオ・C・ハマノ -- gitster--コミット 741a694、2016年4月18日)

branch -m: ワークツリーごとのHEADをすべて更新する

ブランチの名前を変更する場合、現在は現在の作業ツリーの HEAD のみが更新されますが、古いブランチを指すすべての作業ツリーの HEAD を更新する必要があります。

これは現在の動作であり、/path/to/wt の HEAD は更新されません。

 % git worktree list
 /path/to     2c3c5f2 [master]
 /path/to/wt  2c3c5f2 [oldname]
 % git branch -m master master2
 % git worktree list
 /path/to     2c3c5f2 [master2]
 /path/to/wt  2c3c5f2 [oldname]
 % git branch -m oldname newname
 % git worktree list
 /path/to     2c3c5f2 [master2]
 /path/to/wt  0000000 [oldname]

このパッチは、ブランチの名前を変更するときに、関連するすべてのワークツリー HEAD を更新することでこの問題を修正します。


ロック機構はgit 2.10(2016年第3四半期)で正式にサポートされています。

見るコミット 080739bコミット 6d30862コミット 58142c0コミット 346ef53コミット 346ef53コミット 58142c0コミット 346ef53コミット 346ef53(2016年6月13日)コミット 984ad9eコミット 6835314(2016年6月3日)グエン・タイ・ゴック・デュイ ( pclouds)
によって提案されました:エリック・サンシャイン(sunshineco(合併者
ジュニオ・C・ハマノ -- gitster--コミット 2c608e0、2016年7月28日)

git worktree lock [--reason <string>] <worktree>
git worktree unlock <worktree>

リンクされた作業ツリーが、常にマウントされているわけではないポータブル デバイスまたはネットワーク共有に保存されている場合は、作業ツリーがロックされている理由をgit worktree lockオプションで指定してコマンドを発行することにより、管理ファイルが削除されるのを防ぐことができます--reason

<worktree>: 作業ツリーのパスの最後のパス コンポーネントが作業ツリー間で一意である場合、それを使用して作業ツリーを識別できます。
たとえば、" /abc/def/ghi" と " /abc/def/ggg" の 2 つの作業ツリーしかない場合、" ghi" または " def/ghi" は、以前の作業ツリーを指すのに十分です。


Git 2.13 (2017年第2四半期)にlockオプションを追加コミット 507e6e9(2017年4月12日)グエン・タイ・ゴック・デュイ ( pclouds)
によって提案されました:デビッド・テイラー(dt.
協力者:ジェフ・キング(peff(合併者
ジュニオ・C・ハマノ -- gitster--コミット e311597、2017年4月26日)

ワークツリーを作成後すぐにロックできるようにします。これにより、「 」と「 」
間の競合を防ぐことができます。git worktree add; git worktree lockgit worktree prune

はaftergit worktree add' --lockと同等ですが、競合状態はありません。git worktree lockgit worktree add


Git 2.17+ (2018年第2四半期) ではgit worktree move/ が追加されましたgit worktree remove:この回答を見る


Git 2.19 (2018 年第 3 四半期) では、" " の冗長性--quietを減らす " " オプションが追加されましたgit worktree add

見るコミット 371979c(2018年8月15日)エリア・ピント ( devzero2000)
協力者: Martin Ågren[メールアドレス]デュイ・グエン(pclouds、 そしてエリック・サンシャイン(sunshineco(合併者
ジュニオ・C・ハマノ -- gitster--コミット a988ce9、2018年8月27日)

worktree:--quietオプションを追加

他のコマンドと同様に、 に' --quiet' オプションを追加します。 ' ' を除く他のすべてのコマンドは現在デフォルトでサイレントであるため、 ' ' が影響を受ける唯一のコマンドです。git worktreegit
addlist


注意: " git worktree add" は、"stat を使用して使用可能な名前を検索してからmkdir" を実行するために使用されていましたが、これは競合が発生しやすいものでした。これは、ループ内でを使用して に反応する
ことで、Git 2.22 (2019 年第 2 四半期) で修正されました。mkdirEEXIST

見るコミット 7af01f2(2019年2月20日)ミハル・スチャネク ( hramrach)(合併者
ジュニオ・C・ハマノ -- gitster--コミット 20fe798、2019年4月9日)

worktree:worktree addレースを修正

Git は、使用可能なワークツリー名を見つけるために stat ループを実行し、mkdir見つかった名前に対して実行します。
これをループに変更してmkdir、同じ空き名を見つけて最初にディレクトリを作成する worktree add の別の呼び出しを回避します。


Git 2.22 (2019 年第 2 四半期) では、Git リポジトリに作業ツリーがあるかどうかを判断するロジックが修正され、git branch -D現在チェックアウトされているブランチが誤って削除されるのを防ぐようになりました。
このロジックの実装は、珍しい名前のリポジトリでは機能しませんでしたが、残念ながら、最近のサブモジュールではこれが標準となっています。

見るコミット f3534c9(2019年4月19日)ジョナサン・タン(jhowtan(合併者
ジュニオ・C・ハマノ -- gitster--コミット ec2642a、2019年5月8日)

worktree:is_bareヒューリスティックの更新

" " が実行されるとgit branch -D <name>、Git は通常、まずそのブランチが現在チェックアウトされているかどうかを確認します。
ただし、そのリポジトリの Git ディレクトリが " " にない場合、このチェックは実行されません。これは、たとえば、<repo>/.gitそのリポジトリが Git ディレクトリが " " として保存されているサブモジュールである場合に当てはまります。その結果、ブランチはチェックアウトされていても削除されます。super/.git/modules/<repo>

これは、ワークツリーのパスが " " で終わらない場合はリポジトリがベアであり、そうでない場合はベアではないというヒューリスティックを使用してワークツリーのみget_main_worktree()worktree.c設定するためです。このコードはis_bare/.git
is_bare92718b7(「worktree: ワークツリー構造体に詳細を追加する」、2015-10-08、Git v2.7.0-rc0)、pre-core.bareヒューリスティックに従います。

このパッチは次の 2 つのことを行います:

  • get_main_worktree()代わりに使用することを教えるis_bare_repository()、導入7d1864c(「is_bare_repository()とcore.bare設定変数の導入」、2007-01-07、Git v1.5.0-rc1)および更新翻訳(「作業ツリー処理のクリーンアップ」、2007-08-01、Git v1.5.3-rc4)。
    これにより、git branch -D <name>上記の「」問題が解決されます。
    ただし...
  • リポジトリにcore.bare=1" git" コマンドがあるが、そのセカンダリ ワークツリーの 1 つから実行されている場合は、is_bare_repository()false を返します (ワークツリーが使用可能なので問題ありません)。
    また、メイン ワークツリーがベアであるときにそれを非ベアとして扱うと、問題が発生します。たとえば、メイン ワークツリーの HEAD によって参照されるセカンダリ ワークツリーからブランチを削除できない場合、そのメイン ワークツリーがベアである場合でも問題が発生します。

それを避けるためには、core.bareを設定するときにもチェックしてくださいis_bare
の場合はcore.bare=1それを信頼し、そうでない場合は を使用してくださいis_bare_repository()


Git 2.29 (2020 年第 4 四半期) では、「worktree」 API によりワークツリー パスの決定が改善されました。

見るコミット 918d8ffコミット 1c4854eコミット 246756fコミット 62573a5(2020年7月31日)エリック・サンシャイン(sunshineco(合併者
ジュニオ・C・ハマノ -- gitster--コミット 197253e、2020年8月10日)

worktree: 不必要なパスの変更をなくす

署名者: エリック・サンシャイン

の内容は、.git/worktrees/<id>/gitdir" " 形式のパスである必要があります/path/to/worktree/.git。その他の内容は、" " ファイル
が破損していることを示します。gitdir

ワークツリー自体のパスを決定するには、単に「/.git」サフィックスを削除するだけです。これは、ワークツリー パスが最初から決定されていた方法です。

しかし、5193490442(" worktree: ワークツリーの詳細を取得する関数を追加", 2015-10-08, Git v2.7.0-rc0 --マージ記載されているバッチ #7) はパス操作を不思議な方法で拡張しました。パスから
" " を削除できない場合は、代わりに現在の作業ディレクトリをリンクされたワークツリーのパスとして報告します。/.git

if (!strbuf_strip_suffix(&worktree_path, "/.git")) {
    strbuf_reset(&worktree_path);
    strbuf_add_absolute_path(&worktree_path, ".");
    strbuf_strip_suffix(&worktree_path, "/.");
}  

この論理は明らかに間違っている。一般的に正しい行動であるはずがない。それは突然現れた。5193490442それが望ましいケースを示す説明もテストもありません。

このロジックは、破損した " " ファイルを何らかの方法で処理し、何らかのgitdir意味のある値を返すように導入された可能性がありますが、現在の作業ディレクトリを返すことは役に立ちません。実際、これは非常に誤解を招くものです (現在のディレクトリが " " エントリが破損しているワークツリーである場合の特定のケースを除く)。さらに、破損した値について嘘をついて完全に隠すのではなく、ユーザーに報告する方が、問題の診断に役立つ可能性があるため、より役立ちます。gitdir

したがって、この偽のパス変更を削除し、単に「 」を削除するという元の動作にロジックを戻します/.git

おすすめ記事