Gitでブランチを間違えて作業した上にpushまでしちゃった場合の対処方法
時間ができたのでHandBrake 0.9.5の日本語化に着手しているのだが、うっかり0.9.4のブランチで作業してしまったあげく、SourceForge.JP上のリポジトリにpushしてしまい途方に暮れる。
まあこういうミスをやる人は少ないだろうが、何かのヒントになるかもしれないので対処法をメモしておく。まず、「git log」コマンドで巻き戻したいcommitのハッシュを調べる。
$ git log : : commit 1485a5a2bbbb43eedbe131c919b7d604bcbd506d Author: unknownDate: Tue Jan 5 19:19:44 2010 +0900 update Installer, changelog, readme
今回は、この「1485a5a2bbbb43eedbe131c919b7d604bcbd506d」というcommitまで巻き戻すことにする。作業中のブランチが操作したいものであることを確認したうえで、「git reset <対象のハッシュ>」を実行する。
$ git branch -a jp-0.9.3 * jp-0.9.4 master original remotes/origin/HEAD -> origin/master remotes/origin/jp-0.9.3 remotes/origin/jp-0.9.4 remotes/origin/master remotes/origin/original $ git reset 1485a5 Unstaged changes after reset: M Jamrules M Makefile M win/C#/Installer/Installer.nsi M win/C#/InstallerJp/doc/AUTHORS M win/C#/InstallerJp/doc/CREDITS M win/C#/InstallerJp/doc/NEWS M win/C#/Properties/AssemblyInfo.cs M win/C#/frmAbout.Designer.cs
「git log」で巻戻ったことを確認する。
$ git log commit 1485a5a2bbbb43eedbe131c919b7d604bcbd506d Author: unknownDate: Tue Jan 5 19:19:44 2010 +0900 update Installer, changelog, readme
バージョン管理されているファイル自体は巻き戻されていないので、「-f」オプション付きでチェックアウトしてファイルも巻き戻す。
$ git checkout -f
ここまでの作業でローカルブランチの巻き戻しは完了。続いてリモートブランチの巻き戻しを行う。ただし、当然ながらそのままpushすることはできない。
$ git push Enter passphrase for key '/d/Users/hirom/.ssh/id_dsa': To hylom@git.sourceforge.jp:/gitroot/handbrake-jp/handbrake-jp.git ! [rejected] jp-0.9.4 -> jp-0.9.4 (non-fast-forward) error: failed to push some refs to 'hylom@git.sourceforge.jp:/gitroot/handbrake- jp/handbrake-jp.git' To prevent you from losing history, non-fast-forward updates were rejected Merge the remote changes (e.g. 'git pull') before pushing again. See the 'Note about fast-forwards' section of 'git push --help' for details.
そこで、いったんリモートブランチを削除した上で再度pushする。まずは削除。リモートブランチの削除は、「git push <リモートリポジトリ> :<対象リモートブランチ>」で行える。
$ git push origin :jp-0.9.4 Enter passphrase for key '/d/Users/hirom/.ssh/id_dsa': To hylom@git.sourceforge.jp:/gitroot/handbrake-jp/handbrake-jp.git - [deleted] jp-0.9.4
あとは再度ローカルリポジトリをpushするだけ。
$ git push origin jp-0.9.4:jp-0.9.4 Enter passphrase for key '/d/Users/hirom/.ssh/id_dsa': Counting objects: 233, done. Delta compression using up to 2 threads. Compressing objects: 100% (146/146), done. Writing objects: 100% (165/165), 30.48 KiB, done. Total 165 (delta 119), reused 0 (delta 0) To hylom@git.sourceforge.jp:/gitroot/handbrake-jp/handbrake-jp.git * [new branch] jp-0.9.4 -> jp-0.9.4
お粗末様でした。
gitメモ:ブランチを切ってないのにやばいコードを書いちゃった場合
gitを使ってコードの管理をしている場合において、実験的なコードを書く場合はソースコードを編集する前にブランチを作成しておくのが基本だ。しかし、ついブランチを作成し忘れたままでコードを変更してしまった、というパターンがある。
この場合、下記のようにgit stashでいったん変更点を保存した上で直前のcommitに戻し、新たなブランチを作成してそこでgit stash applyを行えばよい。
$ git stash $ git checkout hogehoge -b $ git stash apply $ git add hogehoge foobar $ git commit
git stash、便利だ。
gitメモ:diffとやり直し
最近久しぶりにgitを触って色々と忘れていたので再度メモ。
mergeを取り消す
mergeを実行したらconflictが大量に出てしまったので取り消したい、という場合、下記を実行。
$ git reset --hard ORIG_HEAD
conflictを解決する
gitにはmergeを実行した場合にconflictを解決するコマンド「git mergetool」がある。conflictしているファイルに対して、順番にdiffツールを実行して編集を促すもの。しかし、Windows上のMSysGit環境で実行したら見事にvimのdiffが実行されたので個人的にはデフォルトでは使えない認定(自分はvimはあまり使えないので)。
$ git mergetool
.gitconfigの「merge」および「mergetool」項目で起動するツールを設定できるそうなので、今度はEmacsに設定してテストしてみようかな。
diffを使う
マニュアルに書いてあるけど、「git diff」コマンドの書式は下記のとおり。
git diff <比較元commit> <比較先commit> [<対象ファイルパス>]
ここで、比較元・比較先commitはハッシュだけでなく、「HEAD」(最新のコミット)や「HEAD^」(最新の1つ前のコミット)、「HEAD^^」(最新の2つ前のコミット)、「HEAD~4」(最新の4つ前のコミット)などのほか、tagも利用可能。
例えば最新のコミットと、その1つ前のコミットでdiffを取るには次のようにする。
$ git diff HEAD^ HEAD hogehoge.py
TortoiseGitの記事を書きました
SourceForge.JP Magazineで 実用レベルに達したWindows向けGitクライアント「TortoiseGit」でGitを始めよう を書きました。ふと TortoiseGitのWebページ を見たらバージョンが上がっていて、インストールしてみたらかなり使えるようになっていたので適当に日本語化したうえで記事を書くという、自作自演(笑)。
はてブコメント では「日本語のファイル名に対応していない現状で実用的か?」というものが見られたんですが、日本語ファイルの件はすっかり失念してました。もともとバージョン管理するようなファイル/ディレクトリには日本語のファイル名を使わないもので、一般的にもそうなのかとすっかり思いこんでいたのですが、世間は違うようです……。
ただ、これはTortoiseGitだけの問題ではない話&作者がこれを認識しているか不明なので、TortoiseGitがバージョン1.0になっても解決はされない可能性があります。ということで誰かがパッチを書いて送るべし。
# といっても、コマンドライン版(msysgit/cygwin)との互換性の話もあるので結局はGit本体のほうにファイル名の整合性をとるシステムが入るべきだという気もするのですが
## そして Cygwin 1.7ではコードページの切り替え機能によってUTF-8でファイル名を扱えるという話を初めて知った
gitで特定のファイルを無視させる
gitで特定の拡張子などを持つファイルをtracking対象から外すには、.gitディレクトリがあるディレクトリに.gitignoreファイルで設定すればよい、というのはよく聞かれる話。たとえば自分の場合、下記のように設定することが多い。
*.pyc *~ *.bak
で、毎回これを設定するのは面倒。そんなときは、適当なところにグローバル用の.gitignoreファイルを作成し、git configで そのファイルのパスを「core.excludesfile」に設定すればOK。
$ git config --global --add core.excludesfile "$HOME/.gitignore"