2012-05-25 8 views
10

これは、多くのシナリオでは悪い考えであると私は理解します。私はGitを勉強して実験しています。この練習では、コードは損なわれません。Gitでコミットメッセージの名前を変更するには?

私はこのような構造を作成しました:

* [cf0149e] (HEAD, branch_2) more editing 
* [8fcc106] some edit 
| 
| * [59e643e] (branch_2b) branch 2b 
|/
|/ 
| * [0f4c880] (branch_2_a) branch 2a 
|/
|/ 
* [a74eb2a] checkout 1 
* [9a8dd6a] added branch_2 line 
| 
| 
| * [bb903de] (branch_3) branch 3 
|/ 
| 
| * [674e08c] (branch_1) commit 1 
| * [7d3db01] added branch_1 line 
|/ 
* [328454f] (0.0.0) test 

は今、私はこのグラフを通過し、彼らが意味をなすように、様々なコミットの名前を変更したいです。例えば

[cf0149e] (HEAD, branch_2) more editing 
[59e643e] (branch_2b) branch 2b 
[0f4c880] (branch_2_a) branch 2a 

は全ての外に分岐している:

[a74eb2a] checkout 1 

を私は

git rebase -i 328454f 
を試したこと

* | [a74eb2a] checkout 1 
    * | [9a8dd6a] added branch_2 line 

renamed to: 

    * | [a74eb2a] branch 2 commit 2 
    * | [9a8dd6a] branch 2 commit 1 

注意

は、私が変更したいとリベース処理を継続として、その後

git commit --amend -m "the new message" 

を実行しているコミット上の「編集」に「ピック」に変化します。

このアプローチの問題点は、最後にgit rebase --continueの2つの新しいコミット(私が名前を変更したかった2つの複製)で終了したことです。

* [cf0149e] (HEAD, branch_2) more editing 
* [8fcc106] some edit 
* [3ff23f0] branch 2 commit 2 
* [2f287a1] branch 2 commit 1 
| 
| * [59e643e] (branch_2b) branch 2b 
| /
|/
| | * [0f4c880] (branch_2_a) branch 2a 
| |/
| |/ 
| * [a74eb2a] checkout 1 
| * [9a8dd6a] added branch_2 line 
|/ 
| 
| * [bb903de] (branch_3) branch 3 
|/ 
| 
| * [674e08c] (branch_1) commit 1 
| * [7d3db01] added branch_1 line 
|/ 
* [328454f] (0.0.0) test 

言い換えれば、私は今、まったく同じコードの状態を表すコミットの2セットを持っている:私はリベースを実行した場合たとえば、HEADは「branch_2」であったグラフが次のようになります。

コミットメッセージを変更するだけでした。

また、最初のメッセージの名前を「テスト」から「初期バージョン」に変更したいとします。私はgit commit --amend -m "Initial version"でそれをするように見えることはできません。なぜなら私がチェックアウトするとヘッドレスモードになるからです。

私は間違っていますか?確かにそれは難しいことではありません。

編集:
これは私が試したアプローチです。 もちろん、履歴を書き換えます。非常に特殊なケースの外では、それは悪い考えです。 手順は次のとおりです。

変更するブランチをチェックアウトします。 パッチファイルを作成します。コミットメッセージを変更する

git format-patch HEAD~x // Where x is how far back from HEAD you need to patch 

編集パッチファイルを。 ヘッドをリセットします。

git reset --hard HEAD~x // Same x as before 

のパッチを適用します。

git am 000* 

新しいコミットは、SHA1の新で作成されます。 修正されたメッセージで新しいコミットを参照するブランチがある場合は、それらを移動するにはgit rebaseを使用する必要があります。

私自身の例を使用するには、パッチの手順を適用した後、私はこれでアップを終えた:

* [7761415] (HEAD, branch_2) branch 2 commit 4 
* [286e1b5] branch 2 commit 3 
* [53d638c] branch 2 commit 2 
* [52f82f7] branch 2 commit 1 
| * [bb903de] (branch_3) branch 3 
|/ 
| * [59e643e] (branch_2b) branch 2b 
| | * [0f4c880] (branch_2_a) branch 2a 
| |/ 
| * [a74eb2a] checkout 1 
| * [9a8dd6a] added branch_2 line 
|/ 
| * [674e08c] (branch_1) commit 1 
| * [7d3db01] added branch_1 line 
|/ 
* [328454f] (0.0.0) test 

だから、私は私のbranch_2がうまくラベルコミットしています。 今私は[53d638c] branch 2 commit 2

チェックアウトbranch_2a

git checkout branch_2a 

のうちに分岐が

git rebase 53d638c 

今、私はそれをリベースようbranch_2aを移動したい:

* [fb4d1c5] (HEAD, branch_2a) branch 2a 
| * [7761415] (branch_2) branch 2 commit 4 
| * [286e1b5] branch 2 commit 3 
|/ 
* [53d638c] branch 2 commit 2 
* [52f82f7] branch 2 commit 1 
| * [bb903de] (branch_3) branch 3 
|/ 
| * [59e643e] (branch_2b) branch 2b 
| * [a74eb2a] checkout 1 
| * [9a8dd6a] added branch_2 line 
|/ 
| * [674e08c] (branch_1) commit 1 
| * [7d3db01] added branch_1 line 
|/ 
* [328454f] (0.0.0) test 

同じ手順でbranch_2bの結果は

です
* [ca9ff6c] (HEAD, branch_2b) branch 2b 
| * [fb4d1c5] (branch_2a) branch 2a 
|/ 
| * [7761415] (branch_2) branch 2 commit 4 
| * [286e1b5] branch 2 commit 3 
|/ 
* [53d638c] branch 2 commit 2 
* [52f82f7] branch 2 commit 1 
| * [bb903de] (branch_3) branch 3 
|/ 
| * [674e08c] (branch_1) commit 1 
| * [7d3db01] added branch_1 line 
|/ 
* [328454f] (0.0.0) test 

これはまさに私が探していたものです。 あまりにも乱雑です。もう一度、非常に特殊なケースの外でやりたいことではありません。私の場合、Gitを学ぶために遊んでいるだけなので、実際のコードリポジトリにはあまり影響しません。あなたがする必要がある場合は、これを行うことができることを知ってうれしいです。

最初のコミットの名前を変更します。

+0

できません。 Gitはサーバ指向ではないはずです。他の場所にプッシュすると、それだけです。 –

+3

あなたはどのようにしてあなたの支店とそのすべての素晴らしい図を手に入れましたか?それはgitコマンドか、それともあなた自身でASCIIを使って描いたのですか? –

答えて

16

コミットを実際に変更することはできません。電子メール行の名前のスペルからコミットタイムスタンプの正確な秒まで、どこでも最小限のシングルビット変更を行うと、新しいSHA1とは異なる新しいコミットが得られます(SHA1は "true gitデータベース内の各 "オブジェクト"の "名前"を、4種類のオブジェクトのうちの1つであるコミットと一緒に使用します)。

コミットの変更不可能な部分の1つは、「最近のコミットから最も古いコミットに逆戻りしてチェーンを構築する「親コミット」です。

したがって、どのようなgit rebase -i行い、それぞれが同じ内容のチェーンにコミットして、新しいコミットチェーンを作るです/元などの効果コミットプラスマイナスあなたは対話中行った変更。すべての処理が完了すると、古いコミットチェーンの終わりからラベル(スティッキーノート)が削除され、新しいコミットチェーンの最後に貼り付けられます。これは、最も古いコミットのコピーを変更/リベースすることから始まります。これには、元のチェーンと同じ親コミットか、別の親であることができるrebased親があります。新しいコミットであるため、どちらでもOKです。次に、古いチェーンの次のチェーンのコピーを作成しますが、新しいチェーンをポイントします。それは古いチェーンの終わりまでずっと繰り返されます。

これは、他のすべてのブランチがすべてリベースされたブランチから独立した理由です。彼らはが古いコミットIDを使用しているので、とする必要があります。彼らがあなたの新しい再拠点の支店を枝分かれさせたいなら、あなたはそれぞれの枝に入り、それらを再舗装する必要があります。

強力なSwiss-Army-chainsaw-ishコマンドgit filter-branchがあります。このコマンドを使用すると、非常に大きな一連のコミットをやり直すことができます。ステロイドでgit rebaseのようなものがありますが、この目的のために使用することができます。 (すべてのブランチに影響を与えるには--allで実行します)もちろん、実際にはすべてのコミットをやり直すので、元のレポとは基本的に無関係なレポで終わります。

親がないので、最初のコミット(不可能ではない)を書き直すのは難しいので、普通のrebaseはそれをしません。 (filter-branch can。)これらのSHA1 IDが変更され、あなたのレポをクローンしている人は、それらに依存しているため、通常はこのようなコミットを行うことはできません。誰もあなたがコミットのいくつかの特定のセットに依存していることがわからない場合は、rebaseを好きですが、それはリポジトリの共有部分にあるため、最初のコミットには戻りません。それはかなりまれですが(もちろん「決して」ではありません)、「初期コミット」に至るまでのすべてがあなた自身のプライベートなものです。


私がこれを書いたので、git rebaseはコミット初期のようなコミットルートをコピーするために学んできました。 従来のgit rebase構文を使用すると、ルートの親コミットに名前をつけなければならず、もちろんです(これがグラフの「ルート」になります)。したがって、rebaseは、このケースをカバーするための引数として--rootを使用します。

複数のルートを持つことは可能です。例えば、git checkout --orphanを使用し、続いてgit commitを使用して新しいルートコミットを作成します。 gitソース自体は複数のルーツを持つgitリポジトリに保存されていますが、これは珍しいことです。

+0

OK、それは意味があります。私は一日中実験をして失敗しました。まあ、実際には、私はしなかった、私は多くを学んだ。私は、メッセージをコミットするときには、このことからの主要な離脱は「賢明に選択する」と思う。なぜこのようなことが起こっているのか理解していますが、このような編集を行う手段を提供することは4倍の警告で非常に役立つとも思えません。あなたがコミットメッセージに間違いを犯した場合、あなたは一種のホースです。私の実験は極端なケースで、メッセージを投げた後、「やあ、今それらを理解させてください」と決めました。もちろん、それは非常に難しいものです。 –

+3

だから私の通常のgitでの処理は、私的なブランチ(あるいは多くの私設ブランチ)で作業し、プライベートにしておくことです。そして、物事が準備できたら、再チェックし、必要に応じてコミットをすべて書き直します出版された。すべてのものの最後の "rebase -i"です。 – torek

+0

@torekは、すべてのコミットを再チェックするために大部分のプロジェクトで過度のように思えます...代わりに、準備が整うまでコミットしないでください。間違えても新しいコミットをしてください。ほとんどのユースケースでははるかに簡単です – Paul

関連する問題