term タグ別の記事一覧

Emacsのmagitで使用するgitバイナリのパスを指定する方法

 Xcodeと一緒にインストールしたgitコマンドをEmacsのmagitで使用すると、magitの各種処理がとても遅くなることは皆様ご存知かと思います。また、Xcodeを入れていない環境でmagitを使うと毎回Xcodeをインストールするか確認するダイアログが表示され非常に煩わしかったりします。

 この事象について背景を簡単に説明すると、最近のMacOS環境には/usr/bin/gitがデフォルトで存在するのですが、Xcodeをインストールしていない場合このファイルはただのstubで、実行するとXcodeのインストールを求めるダイアログを表示するという挙動になっています。また、Xcodeをインストールして、Xcode経由でgitをインストールすると、このgitが本物のgitのバイナリに差し替えられるのですが、このgitコマンドはAppleによってカスタマイズされているようで、起動が遅いという問題があります(多分EULAへの同意チェックとかそういうのが入っているっぽい)。そのため普段使いには/usr/local/bin以下に別途gitをインストールして使っている人も多いと思うのですが、magitはデフォルトでまず/usr/bin以下のgitを使う設定になっているので、その場合/usr/local/bin以下のgitが使われません。

 ということで、magitで/usr/local/bin以下のgitを使うようにするには、customize(M-x customize)でCustomize機能を呼び出し、「Exec Path」で検索→Exec Pathに/usr/local/binを追加、という手順で設定する必要があります。

 なお、「Magit Git Exectable」というcustomize項目もあるのですが、こちらを指定してもmagitではまずExec Pathで指定されたパスにgitコマンドを探しに行く模様です。そのため、Xcodeをインストールしていない環境で/usr/local/bin以下にgitをインストールし、Magit Git Executableで「/usr/local/bin/git」を指定した場合、gitに関連する操作をするたびにXcodeのインストールを求めるダイアログが表示される(そしてインストールせずにダイアログを消すと処理が正しく完了する)という面倒な感じになるのでご注意ください。

Gitでブランチを間違えて作業した上にpushまでしちゃった場合の対処方法

 時間ができたのでHandBrake 0.9.5の日本語化に着手しているのだが、うっかり0.9.4のブランチで作業してしまったあげく、SourceForge.JP上のリポジトリにpushしてしまい途方に暮れる。

 まあこういうミスをやる人は少ないだろうが、何かのヒントになるかもしれないので対処法をメモしておく。まず、「git log」コマンドで巻き戻したいcommitのハッシュを調べる。

$ git log
 :
 :
commit 1485a5a2bbbb43eedbe131c919b7d604bcbd506d
Author: unknown <hirom@.(none)>
Date:   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: unknown <hirom@.(none)>
Date:   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"
 

Gitでローカルファイルのバックアップ

 Gitでローカルファイルの差分バックアップをやってみるテスト。

前提:

  • ミラーリングされているファイルサーバーがある
  • いままでは作業用PCがクラッシュしても大丈夫なように、作業後にいちいちファイルをファイルサーバー中のディレクトリに上書きコピーしていた
  • ファイル数が多くなる/容量が大きくなると面倒
  • これだと履歴管理ができない(Emacsの~.1のようなバックアップファイルに頼ることに)

 ということで、下記の手順でGitで差分バックアップをやってみる。

  1. 作業ディレクトリをgitリポジトリ化する。

    $ git init
    $ git add <対象ファイル>
    $ git commit -m “<コメント>”
    

  2. ファイルサーバーにgitのbareリポジトリを作る

    $ cd <バックアップディレクトリ>
    $ mkdir <適当なディレクトリ名>.git
    $ cd <ディレクトリ名>.git
    $ git init –bare
    

  3. ファイルサーバー内のbareリポジトリにコミット

    $ cd <作業ディレクトリ>
    $ git remote add origin <ファイルサーバー上のbareリポジトリのパス>
    $ git push master:master
    

 あとは作業が一段落したタイミングごとにコミット+pushをしていけばいいだけのはず。しかしこういう目的で使い出すとWindows上で動く、使いやすいGUIフロントエンドがほしくなるところではある。