ベンジャクソンの答えはすでに一般的な考えをカバーしていますが、ここで最終的な目標についていくつかのメモ(コメントの価値以上)を追加したいと思います。
2つのブランチを簡単に作成できます。1つは完全にクリーンな(プライベートファイルなし)履歴を持ち、もう1つは完全な(プライベートファイルを含む)もので、コンテンツを適切に共有します。重要なのは、マージ方法に注意することです。過度に単純化された履歴は、次のようになります。
o - o - o - o - o - o - o (public)
\ \ \ \
x ----- x ----x---- x - x (private)
コミットは「o
クリーン」なものであり、x
いくつかの個人情報を含むものです。パブリックからプライベートにマージする限り、何もリークすることなく、両方が必要なすべての共有コンテンツを持つことができます。ベンが言ったように、これには注意する必要があります-他の方法でマージすることはできません。それでも、回避することはかなり可能です-そして、あなたは自分自身をチェリーピッキングに制限する必要はありません。通常の目的のマージワークフローを使用できます。
もちろん、実際には、ワークフローはもう少し複雑になる可能性があります。独自のブランチでトピック(機能/バグ修正)を開発し、それをパブリックバージョンとプライベートバージョンの両方にマージすることができます。たまにさくらんぼを選ぶこともできます。実際には、プライベートをパブリックにマージすることを除いて、何でもあります。
フィルターブランチ
したがって、現在の問題は、リポジトリをこの状態にすることです。残念ながら、これはかなり注意が必要です。プライベートファイルとパブリックファイルの両方にアクセスするコミットがいくつか存在すると仮定すると、最も簡単な方法はfilter-branch
、パブリック(クリーン)バージョンを作成するために使用することだと思います。
git branch public master # create the public branch from current master
git filter-branch --tree-filter ... -- public # filter it (remove private files with a tree filter)
次に、プライベートコンテンツのみを含む一時的なプライベート専用ブランチを作成します。
git branch private-temp master
git filter-branch --tree-filter ... -- private-temp # remove public files
そして最後に、プライベートブランチを作成します。完全なバージョンが1つしかない場合は、次のように1回マージするだけです。
git branch private private-temp
git merge public
これにより、マージが1つだけの履歴が得られます。
o - o - o - o - o - o - o - o - o - o (public)
\
x -- x -- x -- x -- x -- x -- x --- x (private)
注:ここには2つの別々のルートコミットがあります。それは少し奇妙です。それを避けたい場合git rebase --root --onto <SHA1>
は、private-tempブランチ全体をpublicブランチの祖先に移植するために使用できます。
いくつかの中間の完全なバージョンが必要な場合は、まったく同じことを行うことができます。あちこちで停止して、マージしてリベースします。
git checkout -b private <private-SHA1> # use the SHA1 of the first ancestor of private-temp
# you want to merge something from public into
git merge <public-SHA1> # merge a corresponding commit of the public branch
git rebase private private-temp # rebase private-temp to include the merge
git checkout private
git merge <private-SHA1> # use the next SHA1 on private-temp you want to merge into
# this is a fast-forward merge
git merge <public-SHA1> # merge something from public
git rebase private private-temp # and so on and so on...
これにより、次のような履歴が得られます。
o - o - o - o - o - o - o - o - o - o (public)
\ \ \
x -- x -- x -- x -- x -- x -- x --- x (private)
繰り返しになりますが、共通の祖先を持たせたい場合は、イニシャルgit rebase --root --onto ...
を実行して開始できます。
注:履歴にすでにマージがある場合は-p
、リベースでオプションを使用してマージを保持することをお勧めします。
ごまかす
編集:履歴の作り直しが本当に手に負えないことが判明した場合は、いつでも完全にそれをごまかすことができます:すでに持っている同じルートコミットの上に、履歴全体を1つのコミットに押しつぶします。このようなもの:
git checkout public
git reset --soft <root SHA1>
git commit
したがって、これで終わります:
o - A' (public)
\
o - x - o - x - X - A (public@{1}, the previous position of public)
\
x - x (private)
ここでA
、とA'
はまったく同じコンテンツを含みX
、パブリックブランチからすべてのプライベートコンテンツを削除したコミットです。
この時点で、パブリックからプライベートへの単一のマージを実行できます。それ以降は、回答の上部で説明したワークフローに従います。
git checkout private
git merge -s ours public
-s ours
gitに「ours」マージ戦略を使用するように指示します。これは、すべてのコンテンツをプライベートブランチとまったく同じように保持し、パブリックブランチをマージしたことを示すマージコミットを記録するだけであることを意味します。これにより、gitがこれらの「プライベートの削除」X
の変更をコミットからプライベートブランチに適用することを防ぎます。
ルートコミットに個人情報が含まれている場合は、現在のルートコミットの上に一度コミットするのではなく、新しいルートコミットを作成することをお勧めします。