私たちのチームはPHPでいくつかのプロジェクトを行っています。あるプロジェクトのフォルダを別のプロジェクトに誤ってコミットしました。ここで、その特定のコミットをプロジェクトから削除します。プロジェクトから特定のフォルダー/コミットを削除しても、プロジェクトに問題はありません。
フォルダーを削除して現在の位置で新しいコミットを発行すると、フォルダーは削除されますが、Gitの履歴には残ります。そのため、Gitの参照、履歴、その他のものから完全に削除したいと思います。
別のブランチを作成することもできますが、作成者のコミット参照は失われます。その特定のコミットのみを削除したいと思います。履歴の書き換えやリベースには問題はありませんが、その方法がわかりません。
プロジェクトでは、136のコミットを実行し、コミット番号76を削除したいと考えています。 SHAに関する必要な情報は以下のとおりです
5d39775b //136th commit
a4df5ee9 //135th commit
6971cf35 //134th commit
.....
....
162f833c //76th commit
32603274 //75th commit
.....
....
9770059 //1st commit
提供されているすべての方法、つまりリベースとチェリーピックを試しました。私はここで、私が試した方法と私が行ったことの両方に関する完全な情報を提供し、物事をよりよく理解するのに役立ちます
どれが最善かを確認するために、私はこれらのことを行いました。
元のリポジトリがそのままで、物事が簡単に理解できるように、リモートリポジトリをフォークします。したがって、実行されたことが正しいかどうかが確認されるまで、元のリポジトリを実行しないでください。
最初にGitリポジトリのクリーンコピーを取得しました。一般に、ローカルGitデータベースとしてGitに保存されているものを隠したり、他のことをしたりするときはいつでも。そのため、そのGitデータベースにはローカルまたは一時的なものはありません。
フォルダー.gitが使用する合計バイト数を計算しました。リポジトリはクリーンなので、ここでは最小バイトが正しいでしょう。さらに深く掘り下げるために、ディスクで取得されたバイトと取得されたバイトの両方を書き留めました。どちらも異なるものであり、次のとおりです。
バイト-7,963,769およびディスク上のサイズ-8,028,160
Windowsを使用していて、アンチウイルスをインストールしている場合は、アクティブ/リアルタイムモードを無効にする必要があります。物事を行うとき、GitはI/Oファイルチェックへの高速アクセスを必要とします。ファイルがGitによって作成された場合、アクティブモードはウイルスをチェックするために新しいCreatedをロックし、Gitがウイルス対策によるロックのために失敗したことを再アクセスしようとするとどうなりますか。失敗した場合は、1からプロセスを再開しました。
リベース方式では、2つの方法で行うことができます。 1つは--ontoを介して、もう1つは-iを使用します。
次のコマンドを使用しました。
git rebase -i 162f833c^
そしてそれはvimエディターを開いていて、マスターからではなく162f833cから始まるコミットのリストが表示されます。終わりの場合、次の行が提供されます。
# Rebase 3260327..5d39775 onto 3260327
#
# 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
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
コミットが失われるように行を削除してファイルを保存し、エディターを終了しました。終了すると、次のようにリベースが開始されました。
Rebasing ( 1/64) ..(2/64)
Successfully rebased and updated refs/heads/master.
次に、ログをチェックしてコミットが失われたかどうかを確認しようとしましたが、ログに削除したいコミットが見つかりませんでした。コマンドが正常に完了したことを意味します。私はステータスを次のように確認しようとしました:
# On branch master
# Your branch and 'Origin/master' have diverged,
# and have 64 and 65 different commit(s) each, respectively.
コミットは削除されますが、コミットの派生元のリモートではプッシュする必要があるためです。そのため、以前のコードをオーバーライドするように強制してコミットをプッシュしました。
git Push -f
その後、ローカルリポジトリを削除し、リポジトリとそれが示すサイズを再度フェッチしました。
bytes 6,831,765 bytes
size on disk 6,897,664 bytes
多くのブログとマニュアルを読んだ後、私は1つのブログを見つけました ここ それは本当にそれを使用する方法を私に知らせました。したがって、私が使用したコマンドは次のとおりです。
git rebase --onto 3260327 79504a5~1
そして出力は次のとおりです。
First, rewinding head to replay your work on top of it...
Applying: 77th Message
Applying: 78th Message
Applying: 79th Message
....
Last commit
次に、ログをチェックしてコミットが失われたかどうかを確認しようとしましたが、ログに削除したいコミットが見つかりませんでした。コマンドが正常に完了したことを意味します。私はステータスを次のように確認しようとしました:
# On branch master
# Your branch and 'Origin/master' have diverged,
# and have 64 and 65 different commit(s) each, respectively.
したがって、1つのコマンドですべての処理が完了し、次に強制プッシュを実行して、前と同じようにバイトなどをチェックします
git Push -f
その後、ローカルリポジトリを削除し、リポジトリとそれが示すサイズを再度フェッチしました。
bytes - 6,831,389
size on disk - 6,893,568
したがって、リベースメソッドを実行した後。単一のコマンドであり、バイトも-iメソッドよりもわずかに高く保存されるため、間にあるコミットを削除するための--ontoメソッドを本当に承認します。本当の利点は、-ontoメソッドで追加の操作を行う必要がないことです。
Cherry-pickは本当に素晴らしい方法ですが、多くのコマンドを実行するため、コマンドの実行にはほとんど注意を払う必要があります。まず、別のログファイルを作成する必要があります
git log --all --decorate --oneline --graph > 1
何度も表示する必要があるため、リポジトリのログが表示されました。このリポジトリから、削除するコミットを特定し、SHAキーを押して最後の適切なコミットを意味します。これにより、何も変更したくないコミットを特定します。次のコマンドは
git checkout 3260327 -b repair
生成された出力:
Switched to a new branch 'repair'
したがって、最後のグッドコミットまで、新しいブランチを作成しました。したがって、最後のグッドコミットまでのことは変わりません。ここでも、次のコマンドを実行して、すべての適切なコミットを表示します。
git log --decorate --oneline --graph > 2
私は世界を削除しました-すべてとして、私はブランチ修復のコミットのみを表示したいと思います。それが私に示したように、正しくマークされるまでのグッドコミット。次のコマンドは、開始点として不正なコミットが含まれ、最後に実行されたコミットが終了点として含まれているため、注意して使用する必要があります。次のようになります。
git cherry-pick 162f833..5d39775
出力:
[repair 9ed3f18] xxxxxx
x files changed, xxx insertions(+), xx deletions(-)
[repair 7f06d73] xxxxx
xx files changed, xxx insertions(+), xx deletions(-)
.....
...
このコマンドが行うことは、上記で提供された最初のコミット、つまり(162f833)から最後のコミット(5d39775)までを残して、すべてのコミットを再コミットすることです。したがって、sha commitsの値は、コミットを1つずつ再コミットするときに、それに応じて変更されます。次に、ログを次のように表示します。
git log --all --decorate --oneline --graph > 3
として出力:
* f61a9a5 (HEAD, repair) xxxxxx
* 25be3b9 xxxxx
* 49be029 xxxxx
.......
.......
| * 5d39775 (Origin/master, Origin/HEAD, master)
| * a4df5ee xxxxx
| * 6971cf3 xxxxxx
| .......
| .......
| * 162f833 xxxx
|/
* 3260327 xxxxx
......
* 9770059 xxxxx
したがって、グラフを表示すると、不正なコミットを除くすべてのコミットが再コミットされたことがわかります。古いshaキーと新しいキーをすべて表示します。すべて問題がなければ、修復ブランチをマスターとして作成し、マスターブランチを次のように削除する必要があります。
git checkout master
そして出力として:
Switched to branch 'master'
マスターブランチの変更を上書きできるように、最初にマスターブランチをチェックアウトします。次に
git reset --hard 3260327
そして出力として:
HEAD is now at 3260327 xxxxx
正常なコミットの後にコミットが破棄されるため、修復ブランチをマスターとマージする必要があります。
git merge repair
そして出力として:
Updating 3260327..40d290d
Fast-forward
これで、ログを表示しても、不正なコミットは表示されず、すべてが完了します。以前のようにバイトなどをチェックするために強制プッシュを実行しました
git Push -f
その後、ローカルリポジトリを削除し、リポジトリとそれが示すサイズを再度フェッチしました。
bytes - 6,831,556
size on disk - 6,897,664
リベース--onto [First]
bytes - 6,831,389
size on disk - 6,893,568
チェリーピック[2番目]
bytes - 6,831,556
size on disk - 6,897,664
リベース-i [3番目]
bytes 6,831,765 bytes
size on disk 6,897,664 bytes
git rebase --ontoコマンドを優先したいのは、1つのコマンドで簡単に処理できるからです。
マスターブランチでは、インタラクティブにリベースできます。
git rebase -i 162f833c^
これは、コミットに基づいてリベースしますbefore問題のあるコミット。ここで、問題のあるコミットをリストから削除し、保存して、エディターを存在させます(* nixプラットフォームのデフォルトはviです)。
これにより、問題のあるブランチの前に、ブランチをコミットの上にリベースします。これは、達成しようとしていることのようです。
インタラクティブリベースを使用できます。
削除するコミットにはsha1162f833cがあるため、git rebase -i 162f833c^
を実行するだけです。
テキストエディタが開き、コミットのリストが表示されます。削除、保存、および閉じるコミットに対応する行を削除するだけです。
セーフティネットとして、このようなことをするときは、最初にHEADにタグを付けるのが好きです。何か問題が発生した場合は、このタグをチェックアウトして、最初のタグを取得できます。状態。
コミットを自動的に削除し、履歴を書き換えることができます(ここで、${ref_to_delete}
は削除するコミットであり、master
はそれが存在するブランチであると想定しています)。
git rebase --onto ${ref_to_delete}~ ${ref_to_delete} master
リモートリポジトリを使用する場合は、Push
と-f
を使用する必要があります。
git Push -f
これにはgit cherry-pick
を使用することもできます。
$ g # g is my alias for git log --all --decorate --oneline --graph --color
* 618f8e5 [2013-12-14 15:13] (HEAD, master) me: good 6
* e27d6d7 [2013-12-14 15:13] me: good 5
* 533f6c3 [2013-12-14 15:13] me: good 4
* 877585f [2013-12-14 15:13] me: bad
* 00c06f3 [2013-12-14 15:12] me: good 3
* e9f80a4 [2013-12-14 15:12] me: good 2
* 3122ba7 [2013-12-14 15:12] me: good 1
* 98da603 [2013-12-14 15:12] me: first
$ git checkout 00c06f3 -b repair
Switched to a new branch 'repair'
$ git cherry-pick 877585f..618f8e5
[repair b340e21] good 4
1 file changed, 1 insertion(+)
[repair 1d2e0d0] good 5
1 file changed, 1 insertion(+)
[repair 1ed1d19] good 6
1 file changed, 1 insertion(+)
$ g
* 1ed1d19 [2013-12-14 15:13] (HEAD, repair) me: good 6
* 1d2e0d0 [2013-12-14 15:13] me: good 5
* b340e21 [2013-12-14 15:13] me: good 4
| * 618f8e5 [2013-12-14 15:13] (master) me: good 6
| * e27d6d7 [2013-12-14 15:13] me: good 5
| * 533f6c3 [2013-12-14 15:13] me: good 4
| * 877585f [2013-12-14 15:13] me: bad
|/
* 00c06f3 [2013-12-14 15:12] me: good 3
* e9f80a4 [2013-12-14 15:12] me: good 2
* 3122ba7 [2013-12-14 15:12] me: good 1
* 98da603 [2013-12-14 15:12] me: first
$ git checkout master
Switched to branch 'master'
$ git reset --hard repair
HEAD is now at 1ed1d19 good 6
$ git branch -d repair
Deleted branch repair (was 1ed1d19).
$ g
* 1ed1d19 [2013-12-14 15:13] (HEAD, master) me: good 6
* 1d2e0d0 [2013-12-14 15:13] me: good 5
* b340e21 [2013-12-14 15:13] me: good 4
* 00c06f3 [2013-12-14 15:12] me: good 3
* e9f80a4 [2013-12-14 15:12] me: good 2
* 3122ba7 [2013-12-14 15:12] me: good 1
* 98da603 [2013-12-14 15:12] me: first
$ # Done :)
git rebase
の方が良いかもしれないので、少なくともgitには通常複数の方法があることを示しています。結局のところ、リベースは非常に強力なので、「gitで意味のあるすべての操作をリベースコマンドで表現できます」( Linus Torvalds )。
git rebase -i 32603274 ..これにより、コミットの膨大なリストが表示されます。
ピック162f833c ..ピック.。
最初のコミットをd162f833cとして変更します。
そしてそれを保存します。
これにより、76番目のコミットだけが削除されます