1. ホーム
  2. ギット

[解決済み】Gitで複数の作業ディレクトリを作成できますか?

2022-05-06 23:20:36

質問

これがGitでサポートされているものなのかどうかはわかりませんが、理論的にはうまくいくはずだと思います。

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

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

ローカルな git clone ソリューション(デフォルトでは共有オブジェクトをハードリンクし、--shared オプションでは元のレポと別のオブジェクトストアをセットアップします)は知っていますが、これらのソリューションはディスクスペースの使用量を削減するだけで、特に --shared の場合は危険と隣り合わせのようです。

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

解決方法は?

Git 2.5では、2015年7月以降、以下のような置き換えが提案されています。 contrib/workdir/git-new-workdir : ギットワークツリー

参照 コミット 68a2e6a によって ジュニオ・C・ハマノ( gitster ) .

リリースノート :

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

参照 コミット 799767cc9 (Git 2.5rc2)

つまり、以下のことが可能になったということです。 を行う。 git worktree add <path> [<branch>]

作成 <path> をチェックアウトし <branch> をその中に入れる。新しい作業ディレクトリ は現在のリポジトリにリンクされ、作業用の HEAD、index などのディレクトリ固有のファイルです。 そのため 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.pruneworktreesexpiregit config ) を実行することもできます。 git worktree prune を、メインあるいはリンクされた作業ツリーで 古くなった管理用ファイルを一掃する。


警告:まだ git worktree "BUGS" の部分をご覧ください。

<ブロッククオート

に対応した。 サブモジュール が不完全である .

スーパープロジェクトに複数のチェックアウトを行うことは推奨されません。


注意:git 2.7rc1(2015年11月)では、以下のことができるようになりました。 リスト ワークツリー

参照 コミットbb9c03b , コミット 92718b7 , コミット 5193490 , コミット 1ceb7f9 , コミット 1ceb7f9 , コミット 5193490 , コミット 1ceb7f9 , コミット 1ceb7f9 (2015年10月08日)をご参照ください。 コミット 92718b7 , コミット 5193490 , コミット 1ceb7f9 , コミット 1ceb7f9 (2015年10月08日)をご参照ください。 コミット 5193490 , コミット 1ceb7f9 (2015年10月08日)をご参照ください。 コミット 1ceb7f9 (2015年10月8日)、および コミット ac6c561 (2015年10月02日)によるものです。 マイケル・ラパッツォ( rappazzo ) .

(によって統合されました。 ジュニオ・C・ハマノ--。 gitster -- コミット a46dcfb , 2015年10月26日)

<ブロッククオート

worktree : 追加 ' list ' コマンド

' git worktree list ワークツリーのリストを繰り返し、出力します。 ワークツリーの詳細(ワークツリーへのパス、現在の チェックアウトされたリビジョンとブランチ、そして作業ツリーが裸であるかどうか。

$ git worktree リスト /path/to/bare-source(ベアソース) /path/to/linked-worktree abcd1234 [master] (マスター) /path/to/other-linked-worktree 1234abc (デタッチドHEAD)

また、ポーセリンフォーマットのオプションも用意されています。

ポーセリンフォーマットは、1つの属性につき1行です。

  • 属性は、ラベルと値をスペース1つで区切って記載します。
  • ブール値属性('bare' や 'detached' など)はラベルとしてのみ表示され、値が真の場合にのみ存在します。
  • 空白行は、ワークツリーの終端を示します。

例えば

$ 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


注意:ワークツリーフォルダをMOVEする場合、次のことが必要です。 手動で を更新します。 gitdir ファイルを作成します。

参照 コミット618244e (2016年1月22日)、および コミットd4cddd6 (2016年1月18日)による Nguyễn Thái Ngọc Duy ( 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 : 現在チェックアウトされているブランチの削除を拒否する

<ブロッククオート

現在の作業ツリーでブランチがチェックアウトされている場合、ブランチの削除は ブランチは禁止されています。

しかし、そのブランチが他のワーキングツリーからのみチェックアウトされている場合、誤って削除が成功してしまいます。

使用方法 find_shared_symref() のみならず、そのブランチが使用中であるかどうかをチェックするために 現在の作業ツリーのHEADと比較する。


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

参照 コミット 18eb3a9 (2016/04/08)、および コミット 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年06月03日)によるものです。 Nguyễn Thái Ngọc Duy ( 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 "の後に、" ghi "または" def/ghi "であれば、以前のワーキングツリーを指すのに十分です。


Git 2.13 (2017年第2四半期) 追加の lock オプション コミット 507e6e9 (2017年4月12日)による Nguyễn Thái Ngọc Duy ( pclouds ) .

サジェストバイ デビッド・テイラー ( dt ) .

ヘルプドバイ ジェフ・キング ( peff ) .

(によって統合されました。 ジュニオ・C・ハマノ--。 gitster -- コミット e311597 , 2017年4月26日)

<ブロッククオート

ワークツリーを作成後、すぐにロックできるようにしました。

これは、".NETと".NETの間の競合を防ぐのに役立ちます。 git worktree add; git worktree lock と " git worktree prune "です。

そこで git worktree add' --lock は、次のものと同等です。 git worktree lock の後に git 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 ) .

Helped-by: Martin Ågren [email protected] Duy Nguyen ( pclouds ) および エリック・サンシャイン ( sunshineco ) .

(によって統合されました。 ジュニオ・C・ハマノ--。 gitster -- コミット a988ce9 , 2018年8月27日)

<ブロッククオート

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

を追加します。 --quiet というオプションを git worktree のように、他の git コマンドを使用します。

' add を除く他のすべてのコマンドは、この影響を受けるので、'は唯一のコマンドです。 list は、現在デフォルトでサイレントになっています。


なお、" git worktree add 以前は、quot;利用可能な名前をstatで検索していました。 そして mkdir "、これはレースが起こりやすい。

この現象は、Git 2.22 (2019 年第 2 四半期) で、次のように修正されました。 mkdir に反応し EEXIST をループさせる。

参照 コミット 7af01f2 (2019年2月20日)によるものです。 ミハエル・スチャネク ( hramrach ) .

(によって統合されました。 ジュニオ・C・ハマノ--。 gitster -- コミット20fe798 , 2019年04月09日)

<ブロッククオート

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年05月08日)

<ブロッククオート

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_bare のコードが導入されました。 92718b7 (" worktree : add details to worktree struct", 2015-10-08, Git v2.7.0-rc0) に続く。 pre-core.bare ヒューリスティックに

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

  • 教える get_main_worktree() を使用する is_bare_repository() で紹介した 7d1864c ("Introduce is_bare_repository() and core.bare configuration variable", 2007-01-07, Git v1.5.0-rc1) で更新され、さらに e90fdc3 ("Clean up work-tree handling", 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 "です。