ckclark's Blog

Errors = more code2

Find git difftool fix using git bisect

用了 git 一陣子 覺得diff.tool設成vimdiff後有點麻煩 每次都是Read-only的狀態
發現網路上有一個 設定 其實就是去改 git 實作 diff.tool=vimdiffcommand 而已
奇怪的是 照著做後 有一台電腦可以 另一台電腦卻不行
網路上大部分也都說 打開後再設:set noro就好了
不過既然都有一台電腦可行了 當然要把它找出來囉
反覆比較後 發現原來是 git 的版本不一樣(現在想想好像也理所當然)
正巧 git 學了這麼久還沒用過git bisect 來玩玩看好了

以下是git difftool開vimdiff後會顯示[RO]在檔名旁邊的版本

$ git --version
git version 1.7.9.5

$ git config diff.tool
vimdiff

$ git config difftool.vimdiff.cmd
vim -f -d -c "wincmd l" -c 'cd "$GIT_PREFIX"' "$LOCAL" "$REMOTE"

$ git difftool

以下是預期的版本

$ git --version
git version 1.9.1

$ git config diff.tool
vimdiff

$ git config difftool.vimdiff.cmd
vim -f -d -c "wincmd l" -c 'cd "$GIT_PREFIX"' "$LOCAL" "$REMOTE"

$ git difftool

好的 既然知道是版本問題 那就動工吧
首先先把 git 載下來

$ git clone https://github.com/git/git.git
Cloning into 'git'...
remote: Counting objects: 194185, done.
remote: Total 194185 (delta 0), reused 0 (delta 0), pack-reused 194185
Receiving objects: 100% (194185/194185), 67.55 MiB | 426.00 KiB/s, done.
Resolving deltas: 100% (141771/141771), done.
Checking connectivity... done.

接下來 可以開始使用 git bisect
...
...
man了一下 git bisect 才發現這是要拿來找bug不是要找fix的啊
真的要操作下去不就要git bisect good當做還沒修掉, git bisect bad當做修掉了嗎XDD(話說我還真的這樣操作了)
不過問了一下Google大神 祂很親切的告訴我們 何不使用 alias
在加了

[alias]
    bisect-fixed = bisect bad
    bisect-unfixed = bisect good

之後 開始玩吧

[/tmp/git] $ git bisect start

[/tmp/git] $ git bisect-fixed v1.9.1

[/tmp/git] $ git bisect-unfixed v1.7.9.5
Bisecting: 3936 revisions left to test after this (roughly 12 steps)
[b9a5f6811d186ec2420df39e3ec8087c7166a636] Merge branch 'jk/doc-makefile-cleanup'

現在可以看到git幫我們選了一版要讓我們測試了
就給他無腦make下去吧

[/tmp/git] $ make -j8
GIT_VERSION = 1.8.1.2.564.gb9a5f68
    * new build flags
    * new link flags
    * new prefix flags
    GEN common-cmds.h
    CC hex.o
...
    SUBDIR git_remote_helpers
    SUBDIR templates

看似build完了
讓我們試試這版長怎樣

[/tmp/git] $ echo '# hello world' >> .gitignore

[/tmp/git] $ ./git difftool
/tmp/git/./git-difftool--helper: 58: .: Can't open /home/ckclark/libexec/git-core/mergetools/defaults
merge tool candidates: meld opendiff kdiff3 tkdiff xxdiff kompare gvimdiff diffuse ecmerge p4merge araxis bc3 codecompare emerge vimdiff
/tmp/git/./git-difftool--helper: 58: .: Can't open /home/ckclark/libexec/git-core/mergetools/defaults
external diff died, stopping at .gitignore.

這啥
仔細追了一下原來是libexec沒設定好
那改一下Makefile

@@ -371,7 +371,7 @@ bindir_relative = bin
 bindir = $(prefix)/$(bindir_relative)
 mandir = share/man
 infodir = share/info
-gitexecdir = libexec/git-core
+gitexecdir = /tmp/git/
 mergetoolsdir = $(gitexecdir)/mergetools
 sharedir = $(prefix)/share
 gitwebdir = $(sharedir)/gitweb

改完就順便把它git stash一下 之後也方便git stash apply
待會的./git difftool還剛好可以拿來diff這個檔案

在這邊如果想要乾淨回到這個commit checkout的狀態
我是都用

[/tmp/git] $ rm .gitignore
[/tmp/git] $ git clean -df
[/tmp/git] $ git checkout -- .

三連發 連被ignore掉的都要清得乾乾淨淨(這邊沒有仔細去google有沒有比較簡單的command)

好的 讓我們繼續看下去

[/tmp/git] $ git stash show -p
diff --git a/Makefile b/Makefile
index 5a2e02d..7ccfd93 100644
--- a/Makefile
+++ b/Makefile
@@ -371,7 +371,7 @@ bindir_relative = bin
 bindir = $(prefix)/$(bindir_relative)
 mandir = share/man
 infodir = share/info
-gitexecdir = libexec/git-core
+gitexecdir = /tmp/git/
 mergetoolsdir = $(gitexecdir)/mergetools
 sharedir = $(prefix)/share
 gitwebdir = $(sharedir)/gitweb
[/tmp/git] $ git status
HEAD detached at b9a5f68
You are currently bisecting, started from branch 'master'.
  (use "git bisect reset" to get back to the original branch)

nothing to commit, working directory clean

[/tmp/git] $ git stash apply
HEAD detached at b9a5f68
You are currently bisecting, started from branch 'master'.
  (use "git bisect reset" to get back to the original branch)

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   Makefile

no changes added to commit (use "git add" and/or "git commit -a")

[/tmp/git] $ make -j8
...skipped...

[/tmp/git] $ ./git difftool 

看起來這版有fix耶 那可以看下一版了
不過記得要先還原乾淨, git bisect 才會帶入下一版來測

[/tmp/git] $ rm .gitignore
[/tmp/git] $ git clean -df
...
[/tmp/git] $ git checkout -- .
[/tmp/git] $ git bisect-fixed 
Bisecting: 1966 revisions left to test after this (roughly 11 steps)
[c90f06efd84ef0ace0c92509a8bfa1bb1d8b05a8] Merge branch 'mk/test-seq'

然後就 git stash apply && make -j8 && ./git difftoolvimdiff有沒有[RO]在檔名旁邊
接下來clean三連發, git bisect-(un)fixed
再來就依此要領 反覆操作 就不贅述了XD
直接把輸出寫在下面

$ git bisect-unfixed 
Bisecting: 982 revisions left to test after this (roughly 10 steps)
[2739889c98e8d1c1a40263f7f7c0866879c31edf] Merge branch 'jk/config-ignore-duplicates'
...
$ git bisect-fixed
Bisecting: 494 revisions left to test after this (roughly 9 steps)
[8db3865936550fe239b11a44ed52230c3c3eb223] Merge branch 'pw/p4-submit-conflicts'
...
$ git bisect-unfixed 
Bisecting: 246 revisions left to test after this (roughly 8 steps)
[4607a8ce68f4e407bcaaf04819713b40dffce385] Merge branch 'jc/grep-pcre-loose-ends' (early part) into maint
...
$ git bisect-fixed
Bisecting: 124 revisions left to test after this (roughly 7 steps)
[4dbf436bffdf43f91852e23018fc0e45c1bfdab8] Merge branch 'jc/blame-follows-renames'
...
$ git bisect-unfixed
Bisecting: 61 revisions left to test after this (roughly 6 steps)
[b7804cf2277af57785ca0a1686bf6571e711a9ca] Merge branch 'bw/cp-a-is-gnuism'
...
$ git bisect-fixed
Bisecting: 31 revisions left to test after this (roughly 5 steps)
[a967cb15d3eee0d4992f92edab50da0ddbb97738] t9164: Add missing quotes in test
...
$ git bisect-fixed
Bisecting: 12 revisions left to test after this (roughly 4 steps)
[b65f30b6b3bf34831b32a1b209bc1955f2bf79df] Merge branch 'maint'
...
$ git bisect-fixed
Bisecting: 8 revisions left to test after this (roughly 3 steps)
[abc05cbcd3fdc6e5e14daec80c00b6f51b8e4c7e] Merge branch 'jk/completion-tests'
...
$ git bisect-fixed
Bisecting: 4 revisions left to test after this (roughly 2 steps)
[5ec11ab39d11aecd731044955a7a4f7e925cdba6] Merge branch 'da/mergetool-custom'
...
$ git bisect-fixed
Bisecting: 1 revision left to test after this (roughly 1 step)
[69759917aa4b1efb5bf198e76c3664bed9c70d4d] Merge branch 'os/commit-submodule-ignore'
...
$ git bisect-unfixed
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[a427ef7acc9d932d1c203dd2fae67f51c4b1d1e8] mergetool--lib: Allow custom commands to override built-ins

到這邊已經幾乎看到這個fix的comment了

$ git bisect-fixed
a427ef7acc9d932d1c203dd2fae67f51c4b1d1e8 is the first bad commit
commit a427ef7acc9d932d1c203dd2fae67f51c4b1d1e8
Author: David Aguilar <davvid@gmail.com>
Date:   Tue Sep 25 00:48:11 2012 -0700

    mergetool--lib: Allow custom commands to override built-ins

    Allow users to override the default commands provided by the
    mergetools/* scriptlets.

    Users occasionally run into problems where they expect to be
    able to override the built-in tool names.  The documentation
    does not explicitly mention that built-ins cannot be overridden,
    so it's easy to assume that it should work.

    Lift this restriction so that built-in tools are handled the
    same way as user-configured tools.  Add tests to guarantee this
    behavior.

    A nice benefit of this change is that it protects users from
    having future versions of git trump their custom configuration
    with a new built-in tool.

    C.f.:

    http://stackoverflow.com/questions/7435002/mergetool-from-gitconfig-being-ignored
    http://thread.gmane.org/gmane.comp.version-control.msysgit/13188
    http://thread.gmane.org/gmane.comp.version-control.git/148267

    Signed-off-by: David Aguilar <davvid@gmail.com>
    Signed-off-by: Junio C Hamano <gitster@pobox.com>

:100644 100644 f730253c0eac181ec8507d2c837d4ec85a0ae991 6988f9c0c0492b2a623c62420509ef64654c0f1b M  git-mergetool--lib.sh
:040000 040000 8c34016c8fc0698d134f639b5eb3ad6d6fbfacb9 d4f7e06fa45c81f1e4732f7de39b68a275059f14 M  mergetools
:040000 040000 d2750540b7940cb9c7f527fc7b30f402495ba0b3 145371622ea624afcf8ff0a5d7cccb4652585af1 M  t

See patch detail
順便還可以找到這個之前google不到的 SO討論串

打完收工

Comments