私が「master」ブランチに取り入れた変更の1つが GCC2.95 でGitの構築を失敗させる事になりました。 それらは意図的な移植性の修正でしたが、gcc-2.95で動作し続けることも重要でした。 これは、私が、コアGitツールと基本磁器コマンド(barebone Porcelain)を使用して、「master」ブランチの変更を元に戻し、「seen」ブランチを調整するために行ったことです。
最初に、私が物事を台無しちゃった場合に備えて、使い捨てのブランチを準備します。
$ git checkout -b revert-c99 master
今、私は revert-c99
ブランチにいます。 どのコミットを元に戻すかを考えてみましょう。 master
ブランチの先頭がマージであり、そこから2つ目の親(つまり、マージ元の外部コミット)に元に戻したい変更があることを偶然知っています。 さらに、そのマージによって5つのコミットが導入されたことを知っています。
$ git show-branch --more=4 master master^2 | head
* [master] Merge refs/heads/portable from http://www.cs.berkeley....
! [master^2] Replace C99 array initializers with code.
--
- [master] Merge refs/heads/portable from http://www.cs.berkeley....
*+ [master^2] Replace C99 array initializers with code.
*+ [master^2~1] Replace unsetenv() and setenv() with older putenv().
*+ [master^2~2] Include sys/time.h in daemon.c.
*+ [master^2~3] Fix ?: statements.
*+ [master^2~4] Replace zero-length array decls with [].
* [master~1] tutorial note about git branch
上記の --more=4
は、「refのマージベースに到達した後、さらに4つの共通のコミットが表示されるまで表示する」ことを意味します。 その最後のコミットは、「portable」ブランチがメインのgit.gitリポジトリからフォークされた場所であったため、それ以降、両方のブランチのすべてが表示されます。 head
コマンドを使用して、出力を最初の一握りに制限しました。
これで、 master^2~4
(「masterの(複数の親のうち)2番目の親を見つけて、その親から辿って4代前まで遡る(その親自身は1代目)」といいます)が元に戻したいものであることがわかりました。 なぜそれを元に戻すのかについても言及したいので、 -n
フラグが「git revert」に与えられます。 これにより、実際のコミットが行われなくなり、代わりに「git revert」が使用したいコミットログメッセージを「.msg」ファイルに残します:
$ git revert -n master^2~4
$ cat .msg
Revert "Replace zero-length array decls with []."
This reverts 6c5f9baa3bc0d63e141e0afc23110205379905a4 commit.
$ git diff HEAD ;# to make sure what we are reverting makes sense.
$ make CC=gcc-2.95 clean test ;# make sure it fixed the breakage.
$ make clean test ;# make sure it did not cause other breakage.
変更の戻しは道理にかなっており(上記「diff」出力の読み取りのところ)、問題を修正し(上記 make CC=gcc-2.95
テストのところ)、新しい破損を引き起こしません(上記の最後の make test
ののところ)。 私はコミットする準備ができました:
$ git commit -a -s ;# read .msg into the log,
# and explain why I am reverting.
私が上記の手順のいずれかを台無しにする可能性もありましたが、最悪の場合、 git checkout master
を実行して最初からやり直すことができました。 幸いなことに、私はその必要はありませんでした。 私が現在のブランチ revert-c99
に持っているものが、私が欲したものです。 したがって、それを「master」にマージし直します。
$ git checkout master
$ git merge revert-c99 ;# this should be a fast-forward
Updating from 10d781b9caa4f71495c7b34963bef137216f86a8 to e3a693c...
cache.h | 8 ++++----
commit.c | 2 +-
ls-files.c | 2 +-
receive-pack.c | 2 +-
server-info.c | 2 +-
5 files changed, 8 insertions(+), 8 deletions(-)
この時点でテストをやり直す必要はありません。 早送り(fast-forward)すると、 master
が revert-c99
と正確に一致することがわかります。 事実、以下を実行すると:
$ git diff master..revert-c99
これは、何も出力しません。
次に、私達は通常どおり seen
ランチをリベースします。
$ git checkout seen
$ git tag seen-anchor seen
$ git rebase master
* Applying: Redo "revert" using three-way merge machinery.
First trying simple merge strategy to cherry-pick.
* Applying: Remove git-apply-patch-script.
First trying simple merge strategy to cherry-pick.
Simple cherry-pick fails; trying Automatic cherry-pick.
Removing Documentation/git-apply-patch-script.txt
Removing git-apply-patch-script
* Applying: Document "git cherry-pick" and "git revert"
First trying simple merge strategy to cherry-pick.
* Applying: mailinfo and applymbox updates
First trying simple merge strategy to cherry-pick.
* Applying: Show commits in topo order and name all commits.
First trying simple merge strategy to cherry-pick.
* Applying: More documentation updates.
First trying simple merge strategy to cherry-pick.
一時的なタグ seen-anchor
は、「git rebase」が失敗した場合に備えて注意しているだけです。 この後、健全性チェックのために以下を行うことができます:
$ git diff seen-anchor..seen ;# make sure we got the master fix.
$ make CC=gcc-2.95 clean test ;# make sure it fixed the breakage.
$ make clean test ;# make sure it did not cause other breakage.
すべてが順調です。 一時的なブランチやタグはもう必要ないので、削除します:
$ rm -f .git/refs/tags/seen-anchor
$ git branch -d revert-c99
これは緊急の修正(emergency fix)だったので、次のリリースは何日か先になると思いますが、「release candidate」(リリース候補)ブランチにマージした方がいいかもしれませんね。
$ git checkout rc
$ git pull . master
Packing 0 objects
Unpacking 0 objects
* commit-ish: e3a693c... refs/heads/master from .
Trying to merge e3a693c... into 8c1f5f0... using 10d781b...
Committed merge 7fb9b7262a1d1e0a47bbfdcbbcf50ce0635d3f8f
cache.h | 8 ++++----
commit.c | 2 +-
ls-files.c | 2 +-
receive-pack.c | 2 +-
server-info.c | 2 +-
5 files changed, 8 insertions(+), 8 deletions(-)
そして、最終的なリポジトリのステータスは以下のようになります:
$ git show-branch --more=1 master seen rc
! [master] Revert "Replace zero-length array decls with []."
! [seen] git-repack: Add option to repack all objects.
* [rc] Merge refs/heads/master from .
---
+ [seen] git-repack: Add option to repack all objects.
+ [seen~1] More documentation updates.
+ [seen~2] Show commits in topo order and name all commits.
+ [seen~3] mailinfo and applymbox updates
+ [seen~4] Document "git cherry-pick" and "git revert"
+ [seen~5] Remove git-apply-patch-script.
+ [seen~6] Redo "revert" using three-way merge machinery.
- [rc] Merge refs/heads/master from .
++* [master] Revert "Replace zero-length array decls with []."
- [rc~1] Merge refs/heads/master from .
... [master~1] Merge refs/heads/portable from http://www.cs.berkeley....