5

デザイナーとコラボレーションする新しいZendFrameworkプロジェクトを開始しています。私はこのプロジェクトコードをgitを使用して維持し、通常、デザイナーはgit(またはプログラミング言語)を話さないので、彼のために物事を簡単にしたいです。そうしないと、彼はgitをまったく使用しないのではないかと思います。私の計画は彼にいくつかのGitGUIを与えることであり、それで彼はcommit、diff、fetch、merge、push、pullなどの基本的なgit機能のみを使用する必要があります。

gitリポジトリの共有コピーを維持するためにgitoliteを使用しています。これにはきめ細かい権限システムがあるため、専用のブランチ(デザイン)に対してのみデザイナーのRWアクセスを許可し、他のブランチへの読み取りアクセスを許可します。

簡単にするために、メインプロジェクト( ZF推奨の構造に従う)の一部のフォルダーのみを彼と共有したいと思います。彼はその仕事をするためにアクセスする必要があります。同時に、私は私たちの両方がまだお互いからマージできることを望んでいます。

彼のブランチの縮小された構造は次のようになります。

<project name>/
    application/
        layouts/
            scripts/
        views/
            scripts/
    public/
        css/
        images/
        js/

このタスクにサブモジュールを使用できることはわかっていますが、プロジェクトを(少なくとも)4つのサブリポジトリに分割する必要があり、サブリポジトリにのみアクセスでき、3つのリポジトリを使用できるため、維持するのは面倒です。 。このため、これが唯一の解決策である場合、私はこのアイデアをあきらめます。

私がすでに読んだいくつかのリンクは、私が求めていることが可能であると私に思わせます:

これが私の質問です:

  1. 縮小ブランチを作成する方法designgit checkout -b designおよびgit mv/rm?)
  2. ブランチ間で編集を追跡するようにgitを構成する方法(git merge designマスターブランチから、またはその逆を行うことができます)

アップデート:

私はこれらの2つのSOの質問によって与えられた問題への別の可能なアプローチを見つけました

デザインブランチで最初のアフターを実装しようとしgit rm all-unneeded-stuffましたが、マスターブランチでコミットします。これには、ホワイトリストに登録されたパスのファイルとブラックリストに登録されたパスの別のファイルが含まれますがgit merge、次のメッセージで失敗します。

CONFLICT (delete/modify): application/Bootstrap.php deleted in HEAD and modified in master. Version master of application/Bootstrap.php left in tree.

次に、マスターブランチに新しいディレクトリを追加し、デザインからマージするときに新しいディレクトリが追加されます。ドライバーにデバッグエコーを入れましたが、どちらの場合も呼び出されていないことがわかりました。おそらく、実際のマージではないためです。

2番目のアプローチ(.gitignoreのアプローチ)はまだ試していませんが、デザインブランチでブラックリストに登録されたファイルのみを無視するため、このアプローチが私のニーズに合わないことを理解している場合は、デザインブランチ、私の要件を破る。

実験をGitHubにプッシュしました

アップデート2:

現在、その解決策はないと思います。現在のgit実装では、これは単純に達成できません。

矛盾したいのですが、起こらないのではないかと思います。

4

1 に答える 1

6

ディレクトリごとに読み取りアクセスを制限できるようにしたいようです。これは可能ですが、私が知っている唯一の解決策は単純ではありません。これには、サーバー上の同じリポジトリの複数のバージョンが含まれ、それぞれが複雑なフックマジックを使用して同期を維持し、サブディレクトリを除外します。

フックをオープンソースソフトウェアとして(おそらくgitoliteの機能追加として)公開することを最終的な目標として、空き時間にフックの実装に取り​​組んでいますが、残念ながら空き時間は限られています。

リポジトリ

一般的なソリューションには、同じリポジトリの少なくとも3つのバリアントが含まれます。2つ以上のデリゲートリポジトリを調整する1つの権限リポジトリ。ユーザーが権限リポジトリのクローンを作成することはありません。デリゲートリポジトリのみが複製されます。

デリゲートは、着信コミットを権限リポジトリに転送する責任があります。権限リポジトリは、他のデリゲートリポジトリごとに着信コミットを適切にフィルタリングする責任があります。その後、結果は他の代表者にプッシュダウンされます。

権限リポジトリは厳密には必要ありません。デリゲートは独自にフィルタリングを実行し、結果を他のデリゲートに直接プッシュできますが、集中コーディネーターとして別のリポジトリを使用すると、実装が大幅に簡素化されます。

リポジトリの委任

各デリゲートリポジトリには、プロジェクト全体のデータのサブセットが含まれています(たとえば、ゼロ個以上のサブディレクトリが除外されます)。すべてのデリゲートリポジトリは、各デリゲートに異なるファイルのセットが除外されていることを除いて、互いに同一です。それらはすべて同じコミット履歴グラフを持っていますが、コミットは異なるファイルの内容を持ち、したがって異なるSHA1識別子を持ちます。それらには同じブランチとタグのセットがあります(つまり、プロジェクトにmasterブランチがある場合、各デリゲートリポジトリにもmasterブランチがあります)が、同等のコミットのSHA1識別子が異なるため、参照は異なるSHA1を指します。識別子。

たとえば、以下は2つのデリゲートリポジトリのコンテンツのグラフです。everything.gitリポジトリには何も除外されていませんが、リポジトリno-foo.gitにはサブディレクトリ内のすべてがfoo除外されています。

$ cd ~git/repositories/everything.git
$ git log --graph --oneline --decorate --date-order --all
* 2faaad9 (HEAD, master) barbaz
| * c3eb6a9 (release) foobar
* |   8b56913 Merge branch 'release'
|\ \  
| |/  
| * b8f899c qux
* | aad30f1 baz
|/  
* f4acd9f put a new file in subdirectory bar
* 2a15586 put a new file in subdirectory foo

$ cd ~git/repositories/no-foo.git
$ git log --graph --oneline --decorate --date-order --all
* 81c2189 (HEAD, master) barbaz
| * 6bbd85f (release) foobar
* |   c579c4b Merge branch 'release'
|\ \  
| |/  
| * 42c45c7 qux
* | 90ecdc7 baz
|/  
* 4d1cd8d put a new file in subdirectory bar
* 9cc719d put a new file in subdirectory foo

2つのグラフは同じように見え、同じコミットメッセージ、同じブランチ名などを持っていることに注意してください。唯一の違いは、ファイルの内容が異なるため、SHA1IDです。

(補足:コミットもフィルターで除外して、別のデリゲートのユーザーがフィルターで除外されたディレクトリでコミットが行われたことを知らないようにすることができます。ただし、コミットは、フィルターで除外されたディレクトリ内のファイルにのみアクセスする場合にのみフィルターで除外できます。アウトディレクトリ。そうしないと、フックによって自動的に解決できないマージの競合が発生します。)

権限リポジトリ

権限リポジトリは、すべての委任権限のスーパーセットです。各デリゲートリポジトリ内のすべてのコミットオブジェクトは、各デリゲートリポジトリ内のフックを介して権限リポジトリに自動的にプッシュされます。したがって、2つのデリゲートリポジトリがある場合、権限リポジトリに2つの同形DAG(各デリゲートから1つ)があります(デリゲートが共通のルートコミットを共有しないと想定)。

権限リポジトリには、各デリゲートからの各プロジェクトブランチのバージョンがあり、その前にデリゲートの名前が付いています。上記の例を続けると、everything.gitデリゲートリポジトリにはmasterコミットを指すブランチがあり、2faaad9デリゲートにはフィルタリングされているがそれ以外の場合は同等のコミットを指すブランチがあります。このシナリオでは、を指すとを指すという2つのマスターブランチが あります。次のグラフはこれを示しています。no-foo.gitmaster81c2189authority.giteverything/master2faaad9no-foo/master81c2189

$ cd ~git/repositories/authority.git
$ git log --graph --oneline --decorate --date-order --all
* 2faaad9 (everything/master) barbaz
| * 81c2189 (no-foo/master) barbaz
| | * c3eb6a9 (everything/release) foobar
| | | * 6bbd85f (no-foo/release) foobar
* | | |   8b56913 Merge branch 'release'
|\ \ \ \  
| | |/ /  
| |/| |   
| | * |   c579c4b Merge branch 'release'
| | |\ \  
| | | |/  
| * | | b8f899c qux
| | | * 42c45c7 qux
* | | | aad30f1 baz
|/ / /  
| * | 90ecdc7 baz
| |/  
* | f4acd9f put a new file in subdirectory bar
| * 4d1cd8d put a new file in subdirectory bar
* | 2a15586 put a new file in subdirectory foo
 /  
* 9cc719d put a new file in subdirectory foo

各コミットには2つのバージョンがあり、各デリゲートに1つずつあることに注意してください。ブランチ名にも注意してください。

フック

リポジトリの委任

各デリゲートは、権限リポジトリへのコミットをフィードします。

ユーザーがデリゲートリポジトリ内の参照を(経由でgit push)更新すると、そのリポジトリのupdateフックが自動的git pushに権限リポジトリにアクセスします。ただし、標準のプッシュrefspecを使用する代わりに、機関のリポジトリ内の参照の前にデリゲートリポジトリの名前を付けるrefspecを使用します(たとえば、デリゲートリポジトリに名前が付けられている場合は、andfoo.gitのようなプッシュrefspecを使用します)。+refs/heads/master:refs/heads/foo/master+refs/tags/v1.0:refs/tags/foo/v1.0

権限リポジトリ

権限リポジトリは、着信コミットをフィルタリングし、それらを他のデリゲートリポジトリにプッシュダウンします。

デリゲートリポジトリが権限リポジトリにプッシュすると、権限のupdateフックは次のようになります。

  1. ユーザーがフィルターで除外されたディレクトリの1つにファイルを作成しようとしているかどうかを確認します。その場合、エラーで終了します(そうでない場合、自動的に解決できないマージの競合が発生する可能性があります)。
  2. 元々フィルターで除外されていたサブディレクトリに移植して、何もフィルターで除外されていないツリーを形成します。
  3. 他のデリゲートごとに、フィルタリングされていないツリーをフィルタリングして、適切なコンテンツを削除して同等のコミットを行います。
  4. 同等のコミットをデリゲートリポジトリにプッシュします。

デリゲートリポジトリ間の競合状態を回避し、エラーを適切に処理するように注意する必要があります。

あなたの場合

あなたの例では、次のような2つのデリゲートリポジトリがあります。

  • everything.git(あなたのために)
  • zend-project.git(あなたのデザイナーのために)

のブランチにauthority.gitは、プレフィックスが付けられ、2つのデリゲートリポジトリに対応しますeverythingzend-project

にプッシュするmastereverything.git、次のようになります。

  1. フックインupdateeverything.git、着信コミットをのeverything/masterブランチにプッシュしauthority.gitます。
  2. 着信コミットごとに、updateフックインは次のようにauthority.gitなります。
    1. applicationコミットのツリーと100%同一であるが、およびサブディレクトリの外側のすべてを削除する新しいツリーオブジェクトを作成しますpublic
    2. 新しいツリーと同等の親を使用して新しいコミットオブジェクトを作成しますが、元のコミットメッセージ、作成者、およびタイムスタンプを再利用します。
    3. zend-project/master新しいコミットを指すように更新します。
  3. に押し込みます。zend-project/master_authority.gitmasterzend-project.git

デザイナーがプッシュmasterインするzend-project.gitと、次のようになります。

  1. フックインupdatezend-project.git、着信コミットをのzend-project/masterブランチにプッシュしauthority.gitます。
  2. 着信コミットごとに、updateフックインは次のようにauthority.gitなります。
    1. applicationまたはサブディレクトリの外部に新しいファイルが作成されていないかどうかを確認してくださいpublic。その場合は、エラーメッセージを表示して戻ります。
    2. everything/masterに移植された他のサブディレクトリを除いて、コミットのツリーと100%同一の新しいツリーオブジェクトを作成します。
    3. 新しいツリーと同等の親を使用して新しいコミットオブジェクトを作成しますが、元のコミットメッセージ、作成者、およびタイムスタンプを再利用します。
    4. everything/master新しいコミットを指すように更新します。
  3. に押し込みます。everything/master_authority.gitmastereverything.git

ノート

上記は、ディレクトリごとの読み取りアクセス制御を実装する方法を説明しています。特定のユーザーがリポジトリの一部にアクセスできないようにする場合に適しています。あなたの場合、アクセスを制限するよりも、設計者の利便性の方が重要な場合があります。もしそうなら、あなたが望むことを達成するためのより簡単な方法があるかもしれません。

これを十分に明確に説明できたと思います。

于 2011-09-26T04:31:16.170 に答える