2016-05-03 3 views
3

私は作者の情報をgoofed。最初のコミット時にブランチ内で唯一のコミットの場合、最初のコミットのみを削除するにはどうすればよいですか?

しかし、リベースやツリーの変更操作のほとんどは、既存の他のコミットに依存しているようです。

私がGitのインタラクティブなrebaseコマンドを実行しても、私の小さなリストのコミットはすべて1行の "noop"です。 :/(。Gitの木のrootgit rebase -i --rootとに対する私のリベースを実行しているが、最初、私は実際に木からそれを削除しなかった作られたコミットの行を削除することによってこれを解決しよう)

rootの上にリベース

、又は第一コミットしても機能しません。

[[email protected] vagrant]$ git rebase -i HEAD~1 
fatal: Needed a single revision 
invalid upstream HEAD~1 
[[email protected] vagrant]$ git rebase -i HEAD 
Unknown command: rnoop 
Please fix this using 'git rebase --edit-todo'. 
[[email protected] vagrant]$ git rebase --edit-todo 
[[email protected] vagrant]$ git rebase --abort 

以下は、関連する可能な代替の答えのように見えたが、私はもっと何か、あるいは少なくとも、より具体的には、この特殊なケースのための答え価値があると思う:

Delete commits from a branch in Git

この他の回答(How do you undo the last commit?)は、次の結果:ここでは

[[email protected] vagrant]$ git reset --soft HEAD~ 
fatal: ambiguous argument 'HEAD~': unknown revision or path not in the working tree. 
Use '--' to separate paths from revisions, like this: 
'git <command> [<revision>...] -- [<file>...]' 
[[email protected] vagrant]$ git reset --soft HEAD 

、まだこれを読んでそれらのために、vimのバッファがありますnoopと私は前に述べた:それらのため

noop 

# Rebase 3d1c632..3d1c632 onto 3d1c632 (1 command(s)) 
# 
# Commands: 
# p, pick = use commit 
# r, reword = use commit, but edit the commit message 
# e, edit = use commit, but stop for amending 
# s, squash = use commit, but meld into previous commit 
# f, fixup = like "squash", but discard this commit's log message 
# x, exec = run command (the rest of the line) using shell 
# 
# These lines can be re-ordered; they are executed from top to bottom. 
# 
# If you remove a line here THAT COMMIT WILL BE LOST. 
# 
# However, if you remove everything, the rebase will be aborted. 
# 
# Note that empty commits are commented out 

を私はちょうどファイルを編集し、コミット、または何かにそれらを再度追加していない理由を不思議に思って、私は私が持っていた後、私はのみ修正され、間違った著者情報を持っていました"git commit"を実行し、編集のためにコミットメッセージを開いている間に著者情報を変更しました。

おそらく、.gitフォルダ全体を削除しようと思うかもしれませんが、私はよりエレガントな方法を好むでしょう。

さらに、.gitフォルダ全体を削除しなければ、私は自分のフックやものを残しています。この種の質問に対する答えは、私がまだ理解していない基本的な設計原則。

+1

あなたが一人でいたら、あなたのレポだけをコミットしてください。 'git commit --amend'を使うことはできませんか?私はあなたの問題の根底に誤解している可能性が高いです。 – castis

答えて

3

あなたは--rootの上にリベースすることができます

git rebase -i --root 

単にコミット最後に著者を変更するには、この使用:私はあなたが固定の仕組みを通じて働いている参照

git commit --amend --no-edit --author="The Name <[email protected]>" 
+0

// 'git commit --amend --no-edit --author =" ... '、 'Twerked、プロジェクトの最上位ディレクトリに次のように入力します:' $ git commit --amend --no-edit私がインタラクティブなrebaseでコミットを取り除いた後も、それはまだそこにありました。 –

+0

/nautan = "Nathan Bassanese <[email protected]>"しかし、 'git rebase -i -root' /、対話型のrebaseでコミットの行を削除しようとした後、 "フィックスアップ"を適用してログエントリを削除するかどうかを試してみました: '[vagrant @ localhost vagrant] $ git rebase -i --root' ' Can notとにかく思慮深い答えをしてくれてありがとうが、良心的には、私が正常にテストできるようになるまでこれを合格とすることはできないと思う。 –

+0

//特に、 '--amend'と' --author'フラグ付きの 'git commit'コマンドはあるブランチでコミットを変更しましたが、別のブランチでコミットを変更しました。各支店でそれを解除してください。 –

2

を1つの特定の問題。

私もあなたの、より一般的な質問に対処しようとします:

を...私は質問のこの種の答えは、私はまだ理解していないことにGitの基本的な設計原理に話すだろうという感覚を持っています。

ここでは、この特定のプロセスに関連するすべてのトリッキーなビットがあります。

  1. 支店は、(のようなmaster)コミット特定の1つに指し示す可動ポインタです。
  2. 各コミットはその親コミットを指します。 A ルートコミットには、定義上、親はありません。 (ここでは関係なく、知っておくと便利されない:任意のは、少なくとも2人の親にコミットとしてコミットマージを単純に定義されている)
  3. コミット任意のを作成するために、我々はそれだけには、枝の上にする必要がありますルートコミットを作成します。これには親がありません。ブランチにコミットが必要ですが、ポイント#1を参照する必要があります。ブランチ名がコミットを指しています。
  4. Rebaseは、ターゲットから作成された匿名ブランチで、git cherry-pickオペレーションを繰り返し実行します。 (チェリーピッキングが繰り返されると、新しい匿名ブランチチップコミットが元のブランチチップコミットを置き換えます。つまり、ブランチを新しいヒントに再ポイントします)。git cherry-pickgit cherry-pickはコミットを親。たとえば、親に3つのファイルがあり、選択されたコミットが4つの場合、コミットによって新しいファイルが追加されます。 3つのキャストオーバーされたファイルのうちの1つだけが異なっていても、その1つのファイルで変更されたものは残りの部分を構成します(コミットの作成者やその他のメタデータもカウントされます:ピック)。元のコミットを一連の変更に変えた後、Gitはと同じの変更を他に(すでに存在する)コミットしてコミットします。新しいコミットの親はもう一方のコミットです。

これらの原則は、Gordian knot that --root slices throughを作成します。また、--rootはGitバージョン1.6.2で新しくなっており、1.7.12で大幅に変更されています(以前はリベースしていて、いくつかの問題に遭遇しました)。

Gitは常に#1と#3の間の緊張を解決しなければなりませんでした(git checkout--orphanオプションに成長したときに、解決策自体が改善され、適切に形式化されました)。ここでのトリックは、 "誕生していないブランチ"と呼ばれるもので、現在のブランチを通常のようにHEADに記録しますが、ブランチ名自体は作成されません。

(ここでは、これは気にならない実装の詳細ですが、分岐ポインタは現在2つの場所の一方または両方に格納されています。これらの名前とIDのマッピング.git/refs/および/または単一のフラットテキストファイル、.git/packed-refsの小さな個々のファイルに。支店名がどちらの場所にあるが、HEADであれば、Gitはこの「胎児のブランチ」と考えています。)

行うとき新しいコミットは、現在の状態が "未熟成ブランチ"の場合、Gitはルートコミットを行います。新しいコミットIDは、今作成されたブランチのIDになります。ブランチ上にあり、コミットしていないという自己矛盾した状態から外れています。

git cherry-pickは、コミットとその親を比較することで問題が解決します。このため、マージコミットをチェリーピックしたい場合、を指定する必要があります。親:マージは2つ以上の親を持つコミットであるため、どちらを相違させるべきか明確ではありません。しかし、ルートコミットについては、ゼロカウントのゼロの両親をすべて抱えていますか?

Gitはチェリーピックされたルートコミットとthe empty treeを比較することでこの特定の問題を解決します。空のツリーは空であるため、すべてのファイルが新たに追加されます。これがcherry-pickの正しい結果です。

したがって、--rootでリベースするには、孤立したブランチを作成してから、チェリーピックでルートコミットを行い、残りのすべてのコミットをいつものようにしたいと考えています。しかし、git rebaseは、匿名ブランチを使用しています。孤児ブランチを作成する通常の方法はですが、rebaseは "detached HEAD"モードを使用します。さらに、最初のものを含むチェリーピックは、既存のコミットに変更を加える必要がありますが、新しいルートコミットを作成するには、既存の親をいくつか使用する必要がありません。

このための巧妙な内部構造は、this commit to the Git codeにリンクするthis answer from VonCに(間接的に)見つかっています。 rebaseスクリプトは空のツリーを使用して真に空のルートコミットを作成し、git commit-tree内部の "plumbing"コマンドを使用して、ユーザー指定の親IDを持つコミットオブジェクトを作成します。その後、既存の "squash"ルートコミット(同じ空のツリーに対してチェリーピックの差分を持つ)を作成し、それをダミーの空のルートコミットと結合します。

(ここでは、それはまた、リベース中に「スカッシュ」操作は「以前はコミット改正」を意味していることに注意するのに役立ちます、ラgit commit --amend--amend操作を行うためにgit commitを伝える新しいコミット既存のものをすることはできません変更-が、新しいコミットの親を既存のコミットの親に一致させるために、これは古いコミットを脇に押しつける効果があります:ブランチは新しいコミットを指します。これは "変更された"コミットの親を指します。リポジトリ内の他の方法が見つからない限り、と表示されなくなりました。

(この2ステップトリックとは、著者情報が特別に扱われることを意味します)この主張の目的のために


は、少なくとも、デタッチHEADモードである( git checkout hashまたは git checkout --detach branchname後、例えば)は、その先端現在のコミットのハッシュで、特別な匿名の枝の上にあるものとしてカウント。

+0

//私はもっと眠ったときにこれを読むつもりですが、私の最初の印象は、上記のポイント#1とポイント#3との間の矛盾から「初めての」コミットを取り除くことが難しいということです。 「空の木」を私の注意を引くこと、そして思慮深い答えに感謝します。 –

+2

Gitは、置き換えコミットがあるまで、つまり最初のコミットを決して実際には削除しない限り、ブランチポインタを移動させないことで、それを "解決"します。 (実際には、 'git gc'とその配管を除いて、gitはコミットやその他のオブジェクトを決して削除しません。これは既存のオブジェクトに変更を加えずに新しいものを追加することです。 )既存のコミット 'E'でプランを開始し、新しいチェリーピックされたコミットを追加し、最初のピック結果が親なしであると想定されている場合は、問題があります。 :-) – torek

+0

//私は確かに、最初のコミットを「いいえ」とすることができますか? –

関連する問題