Merge branch 'maint'
authorJunio C Hamano <junkio@cox.net>
Wed, 21 Feb 2007 19:16:20 +0000 (11:16 -0800)
committerJunio C Hamano <junkio@cox.net>
Wed, 21 Feb 2007 19:16:20 +0000 (11:16 -0800)
* maint:
Use gunzip -c over gzcat in import-tars example.
git-gui: Don't crash in citool mode on initial commit.
git-gui: Remove TODO list.
git-gui: Include browser in our usage message.
git-gui: Change summary of git-gui.
git-gui: Display all authors of git-gui.
git-gui: Use mixed path for docs on Cygwin.
git-gui: Correct crash when saving options in blame mode.
git-gui: Expose the browser as a subcommand.
git-gui: Create new branches from a tag.
git-gui: Prefer version file over git-describe.
git-gui: Print version on the console.
git-gui: More consistently display the application name.
git-gui: Permit merging tags into the current branch.
git-gui: Basic version check to ensure git 1.5.0 or later is used.
git-gui: Refactor 'exec git subcmd' idiom.

contrib/fast-import/import-tars.perl
git-gui/.gitignore
git-gui/CREDITS-GEN [new file with mode: 0755]
git-gui/GIT-VERSION-GEN
git-gui/Makefile
git-gui/TODO [deleted file]
git-gui/git-gui.sh
index 990c9e70b280fe85bc01869312114f677ee0647d..5585a8b2c575f92e6154e03641b467e5e54509f4 100755 (executable)
        my $tar_name = $1;
 
        if ($tar_name =~ s/\.(tar\.gz|tgz)$//) {
-               open(I, '-|', 'gzcat', $tar_file) or die "Unable to gzcat $tar_file: $!\n";
+               open(I, '-|', 'gunzip', '-c', $tar_file)
+                       or die "Unable to gunzip -c $tar_file: $!\n";
        } elsif ($tar_name =~ s/\.(tar\.bz2|tbz2)$//) {
-               open(I, '-|', 'bzcat', $tar_file) or die "Unable to bzcat $tar_file: $!\n";
+               open(I, '-|', 'bunzip2', '-c', $tar_file)
+                       or die "Unable to bunzip2 -c $tar_file: $!\n";
        } elsif ($tar_name =~ s/\.tar\.Z$//) {
-               open(I, '-|', 'zcat', $tar_file) or die "Unable to zcat $tar_file: $!\n";
+               open(I, '-|', 'uncompress', '-c', $tar_file)
+                       or die "Unable to uncompress -c $tar_file: $!\n";
        } elsif ($tar_name =~ s/\.tar$//) {
                open(I, $tar_file) or die "Unable to open $tar_file: $!\n";
        } else {
index c714d382e87b5c18609f5934890c8b135a720262..805ca2e1c7875fcc9c588dbee5041929c0e451d3 100644 (file)
@@ -1,3 +1,4 @@
+CREDITS-FILE
 GIT-VERSION-FILE
 git-citool
 git-gui
diff --git a/git-gui/CREDITS-GEN b/git-gui/CREDITS-GEN
new file mode 100755 (executable)
index 0000000..da2c076
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+CF=CREDITS-FILE
+tip=
+
+tree_search ()
+{
+       head=$1
+       tree=$2
+       for p in $(git rev-list --parents --max-count=1 $head 2>/dev/null)
+       do
+               test $tree = $(git rev-parse $p^{tree} 2>/dev/null) &&
+               vn=$(git describe --abbrev=4 $p 2>/dev/null) &&
+               case "$vn" in
+               gitgui-[0-9]*) echo $p; break;;
+               esac
+       done
+}
+
+generate_credits ()
+{
+       tip=$1 &&
+       rm -f $CF &&
+       git shortlog -n -s $tip | sed 's/: .*$//' >$CF || exit
+}
+
+# Always use the tarball credits file if found, just
+# in case we are somehow contained in a larger git
+# repository that doesn't actually track our state.
+# (At least one package manager is doing this.)
+#
+# We may be a subproject, so try looking for the merge
+# commit that supplied this directory content if we are
+# not at the toplevel.  We probably will always be the
+# second parent in the commit, but we shouldn't rely on
+# that fact.
+#
+
+if test -f credits
+then
+       rm -f $CF &&
+       cp credits $CF || exit
+elif prefix="$(git rev-parse --show-prefix 2>/dev/null)" &&
+   test -n "$prefix" &&
+   head=$(git rev-list --max-count=1 HEAD -- . 2>/dev/null) &&
+   tree=$(git rev-parse --verify "HEAD:$prefix" 2>/dev/null) &&
+   tip=$(tree_search $head $tree) &&
+   test -n "$tip"
+then
+       generate_credits $tip || exit
+elif tip="$(git rev-parse --verify HEAD 2>/dev/null)" &&
+   test -n "$tip"
+then
+       generate_credits $tip || exit
+else
+       echo "error: Cannot locate authorship information." >&2
+       exit 1
+fi
index 9966126da2682f7b7d65b71a3225dddd1b5fe55b..2741c1e14c4f38b33d10c1679b48c4fc5d9c5587 100755 (executable)
@@ -20,6 +20,11 @@ tree_search ()
        done
 }
 
+# Always use the tarball version file if found, just
+# in case we are somehow contained in a larger git
+# repository that doesn't actually track our state.
+# (At least one package manager is doing this.)
+#
 # We may be a subproject, so try looking for the merge
 # commit that supplied this directory content if we are
 # not at the toplevel.  We probably will always be the
@@ -27,10 +32,13 @@ tree_search ()
 # that fact.
 #
 # If we are at the toplevel or the merge assumption fails
-# try looking for a gitgui-* tag, or fallback onto the
-# distributed version file.
+# try looking for a gitgui-* tag.
 
-if prefix="$(git rev-parse --show-prefix 2>/dev/null)"
+if test -f version &&
+   VN=$(cat version)
+then
+       : happy
+elif prefix="$(git rev-parse --show-prefix 2>/dev/null)"
    test -n "$prefix" &&
    head=$(git rev-list --max-count=1 HEAD -- . 2>/dev/null) &&
    tree=$(git rev-parse --verify "HEAD:$prefix" 2>/dev/null) &&
@@ -48,9 +56,6 @@ elif VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
    esac
 then
        VN=$(echo "$VN" | sed -e 's/^gitgui-//;s/-/./g');
-elif test -f version
-then
-       VN=$(cat version) || VN="$DEF_VER"
 else
        VN="$DEF_VER"
 fi
index fd82d9d16dd17d1030c4414f6a30af56ed4deaa1..66538ba1adb9d50b80288f9ae3c0df77758059aa 100644 (file)
@@ -4,9 +4,8 @@ GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
        @$(SHELL_PATH) ./GIT-VERSION-GEN
 -include GIT-VERSION-FILE
 
-SCRIPT_SH = git-gui.sh
 GITGUI_BUILT_INS = git-citool
-ALL_PROGRAMS = $(GITGUI_BUILT_INS) $(patsubst %.sh,%,$(SCRIPT_SH))
+ALL_PROGRAMS = git-gui $(GITGUI_BUILT_INS)
 
 ifndef SHELL_PATH
        SHELL_PATH = /bin/sh
@@ -24,20 +23,24 @@ DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
 gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
 SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
 
-$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
+git-gui: git-gui.sh GIT-VERSION-FILE CREDITS-FILE
        rm -f $@ $@+
-       sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
+       sed -n \
+               -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
                -e 's/@@GITGUI_VERSION@@/$(GITGUI_VERSION)/g' \
+               -e '1,/^set gitgui_credits /p' \
                $@.sh >$@+
+       cat CREDITS-FILE >>$@+
+       sed -e '1,/^set gitgui_credits /d' $@.sh >>$@+
        chmod +x $@+
        mv $@+ $@
 
+CREDITS-FILE: CREDITS-GEN .FORCE-CREDITS-FILE
+       $(SHELL_PATH) ./CREDITS-GEN
+
 $(GITGUI_BUILT_INS): git-gui
        rm -f $@ && ln git-gui $@
 
-# These can record GITGUI_VERSION
-$(patsubst %.sh,%,$(SCRIPT_SH)): GIT-VERSION-FILE
-
 all:: $(ALL_PROGRAMS)
 
 install: all
@@ -45,12 +48,14 @@ install: all
        $(INSTALL) git-gui '$(DESTDIR_SQ)$(gitexecdir_SQ)'
        $(foreach p,$(GITGUI_BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;)
 
-dist-version:
+dist-version: CREDITS-FILE
        @mkdir -p $(TARDIR)
        @echo $(GITGUI_VERSION) > $(TARDIR)/version
+       @cat CREDITS-FILE > $(TARDIR)/credits
 
 clean::
-       rm -f $(ALL_PROGRAMS) GIT-VERSION-FILE
+       rm -f $(ALL_PROGRAMS) GIT-VERSION-FILE CREDITS-FILE
 
 .PHONY: all install dist-version clean
 .PHONY: .FORCE-GIT-VERSION-FILE
+.PHONY: .FORCE-CREDITS-FILE
diff --git a/git-gui/TODO b/git-gui/TODO
deleted file mode 100644 (file)
index b95a137..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-Items outstanding:
-
- * Add file to .gitignore or info/excludes.
-
- * Populate the pull menu with local branches.
-
- * Make use of the new default merge data stored in repo-config.
-
- * Checkout a different local branch.
-
- * Push any local branch to a remote branch.
-
- * Merge any local branches through a real merge UI.
-
- * Allow user to define keyboard shortcuts for frequently used fetch
-   or merge operations.  Or maybe just define a keyboard shortcut
-   for default fetch/default merge of current branch is enough;
-   but I do know a few users who merge a couple of common branches
-   also into the same branch so one default isn't quite enough.
-
- * Better organize fetch/push/pull console windows.
-
- * Clone UI (to download a new repository).
-
- * Remotes editor (for .git/config format only).
-
- * Show a shortlog of the last couple of commits in the main window,
-   to give the user warm fuzzy feelings that we have their data
-   saved.  Actually this may be the set of commits not yet in
-   the upstream (aka default merge branch remote repository).
-
- * GUI configuration editor for options listed in
-   git.git/Documentation/config.txt.  Ideally this would
-   parse that file and generate the options dialog from
-   the documentation itself, and include the help text
-   from the documentation as part of the UI somehow.
-
-Known bugs:
-
- * git-gui sometimes just closes on Windows with no error message.
-   I'm not sure what the problem is here.  I suspect the wish
-   process is just terminating due to a segfault or something,
-   as the do_quit proc in git-gui doesn't run.  It often seems to
-   occur while writing a commit message in the buffer.  Odd.
index f5010dd47a0416eb18d823f257f4748fec621074..f84ba3382b3078ee6de45bddfacd650973068303 100755 (executable)
@@ -4,7 +4,7 @@ exec wish "$0" -- "$@"
 
 set appvers {@@GITGUI_VERSION@@}
 set copyright {
-Copyright © 2006, 2007 Shawn Pearce, Paul Mackerras.
+Copyright © 2006, 2007 Shawn Pearce, et. al.
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -19,6 +19,9 @@ GNU General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA}
+set gitgui_credits {
+Paul Mackerras
+}
 
 ######################################################################
 ##
@@ -46,7 +49,7 @@ proc gitdir {args} {
 proc gitexec {args} {
        global _gitexec
        if {$_gitexec eq {}} {
-               if {[catch {set _gitexec [exec git --exec-path]} err]} {
+               if {[catch {set _gitexec [git --exec-path]} err]} {
                        error "Git not installed?\n\n$err"
                }
        }
@@ -202,14 +205,14 @@ proc save_config {} {
                set value $global_config_new($name)
                if {$value ne $global_config($name)} {
                        if {$value eq $default_config($name)} {
-                               catch {exec git config --global --unset $name}
+                               catch {git config --global --unset $name}
                        } else {
                                regsub -all "\[{}\]" $value {"} value
-                               exec git config --global $name $value
+                               git config --global $name $value
                        }
                        set global_config($name) $value
                        if {$value eq $repo_config($name)} {
-                               catch {exec git config --unset $name}
+                               catch {git config --unset $name}
                                set repo_config($name) $value
                        }
                }
@@ -219,16 +222,24 @@ proc save_config {} {
                set value $repo_config_new($name)
                if {$value ne $repo_config($name)} {
                        if {$value eq $global_config($name)} {
-                               catch {exec git config --unset $name}
+                               catch {git config --unset $name}
                        } else {
                                regsub -all "\[{}\]" $value {"} value
-                               exec git config $name $value
+                               git config $name $value
                        }
                        set repo_config($name) $value
                }
        }
 }
 
+######################################################################
+##
+## handy utils
+
+proc git {args} {
+       return [eval exec git $args]
+}
+
 proc error_popup {msg} {
        set title [appname]
        if {[reponame] ne {}} {
@@ -287,12 +298,44 @@ proc ask_popup {msg} {
                -message $msg]
 }
 
+######################################################################
+##
+## version check
+
+set req_maj 1
+set req_min 5
+
+if {[catch {set v [git --version]} err]} {
+       catch {wm withdraw .}
+       error_popup "Cannot determine Git version:
+
+$err
+
+[appname] requires Git $req_maj.$req_min or later."
+       exit 1
+}
+if {[regexp {^git version (\d+)\.(\d+)} $v _junk act_maj act_min]} {
+       if {$act_maj < $req_maj
+               || ($act_maj == $req_maj && $act_min < $req_min)} {
+               catch {wm withdraw .}
+               error_popup "[appname] requires Git $req_maj.$req_min or later.
+
+You are using $v."
+               exit 1
+       }
+} else {
+       catch {wm withdraw .}
+       error_popup "Cannot parse Git version string:\n\n$v"
+       exit 1
+}
+unset -nocomplain v _junk act_maj act_min req_maj req_min
+
 ######################################################################
 ##
 ## repository setup
 
 if {   [catch {set _gitdir $env(GIT_DIR)}]
-       && [catch {set _gitdir [exec git rev-parse --git-dir]} err]} {
+       && [catch {set _gitdir [git rev-parse --git-dir]} err]} {
        catch {wm withdraw .}
        error_popup "Cannot find the git directory:\n\n$err"
        exit 1
@@ -319,6 +362,24 @@ set _reponame [lindex [file split \
        [file normalize [file dirname $_gitdir]]] \
        end]
 
+######################################################################
+##
+## global init
+
+set current_diff_path {}
+set current_diff_side {}
+set diff_actions [list]
+set ui_status_value {Initializing...}
+
+set HEAD {}
+set PARENT {}
+set MERGE_HEAD [list]
+set commit_type {}
+set empty_tree {}
+set current_branch {}
+set current_diff_path {}
+set selected_commit_type new
+
 ######################################################################
 ##
 ## task management
@@ -365,7 +426,7 @@ proc repository_state {ctvar hdvar mhvar} {
 
        set mh [list]
 
-       if {[catch {set current_branch [exec git symbolic-ref HEAD]}]} {
+       if {[catch {set current_branch [git symbolic-ref HEAD]}]} {
                set current_branch {}
        } else {
                regsub ^refs/((heads|tags|remotes)/)? \
@@ -374,7 +435,7 @@ proc repository_state {ctvar hdvar mhvar} {
                        current_branch
        }
 
-       if {[catch {set hd [exec git rev-parse --verify HEAD]}]} {
+       if {[catch {set hd [git rev-parse --verify HEAD]}]} {
                set hd {}
                set ct initial
                return
@@ -402,7 +463,7 @@ proc PARENT {} {
                return $p
        }
        if {$empty_tree eq {}} {
-               set empty_tree [exec git mktree << {}]
+               set empty_tree [git mktree << {}]
        }
        return $empty_tree
 }
@@ -642,8 +703,9 @@ proc reshow_diff {} {
        global current_diff_path current_diff_side
 
        set p $current_diff_path
-       if {$p eq {}
-               || $current_diff_side eq {}
+       if {$p eq {}} {
+               # No diff is being shown.
+       } elseif {$current_diff_side eq {}
                || [catch {set s $file_states($p)}]
                || [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} {
                clear_diff
@@ -1042,7 +1104,7 @@ proc committer_ident {} {
        global GIT_COMMITTER_IDENT
 
        if {$GIT_COMMITTER_IDENT eq {}} {
-               if {[catch {set me [exec git var GIT_COMMITTER_IDENT]} err]} {
+               if {[catch {set me [git var GIT_COMMITTER_IDENT]} err]} {
                        error_popup "Unable to obtain your identity:\n\n$err"
                        return {}
                }
@@ -1256,14 +1318,6 @@ proc commit_committree {fd_wt curHEAD msg} {
                return
        }
 
-       # -- Make sure our current branch exists.
-       #
-       if {$commit_type eq {initial}} {
-               lappend all_heads $current_branch
-               set all_heads [lsort -unique $all_heads]
-               populate_branch_menu
-       }
-
        # -- Cleanup after ourselves.
        #
        catch {file delete $msg_p}
@@ -1275,7 +1329,7 @@ proc commit_committree {fd_wt curHEAD msg} {
        # -- Let rerere do its thing.
        #
        if {[file isdirectory [gitdir rr-cache]]} {
-               catch {exec git rerere}
+               catch {git rerere}
        }
 
        # -- Run the post-commit hook.
@@ -1299,6 +1353,14 @@ proc commit_committree {fd_wt curHEAD msg} {
 
        if {[is_enabled singlecommit]} do_quit
 
+       # -- Make sure our current branch exists.
+       #
+       if {$commit_type eq {initial}} {
+               lappend all_heads $current_branch
+               set all_heads [lsort -unique $all_heads]
+               populate_branch_menu
+       }
+
        # -- Update in memory status
        #
        set selected_commit_type new
@@ -1876,11 +1938,24 @@ proc all_tracking_branches {} {
        return [lsort -unique $all_trackings]
 }
 
+proc load_all_tags {} {
+       set all_tags [list]
+       set fd [open "| git for-each-ref --format=%(refname) refs/tags" r]
+       while {[gets $fd line] > 0} {
+               if {![regsub ^refs/tags/ $line {} name]} continue
+               lappend all_tags $name
+       }
+       close $fd
+
+       return [lsort $all_tags]
+}
+
 proc do_create_branch_action {w} {
        global all_heads null_sha1 repo_config
        global create_branch_checkout create_branch_revtype
        global create_branch_head create_branch_trackinghead
        global create_branch_name create_branch_revexp
+       global create_branch_tag
 
        set newbranch $create_branch_name
        if {$newbranch eq {}
@@ -1894,7 +1969,7 @@ proc do_create_branch_action {w} {
                focus $w.desc.name_t
                return
        }
-       if {![catch {exec git show-ref --verify -- "refs/heads/$newbranch"}]} {
+       if {![catch {git show-ref --verify -- "refs/heads/$newbranch"}]} {
                tk_messageBox \
                        -icon error \
                        -type ok \
@@ -1904,7 +1979,7 @@ proc do_create_branch_action {w} {
                focus $w.desc.name_t
                return
        }
-       if {[catch {exec git check-ref-format "heads/$newbranch"}]} {
+       if {[catch {git check-ref-format "heads/$newbranch"}]} {
                tk_messageBox \
                        -icon error \
                        -type ok \
@@ -1919,9 +1994,10 @@ proc do_create_branch_action {w} {
        switch -- $create_branch_revtype {
        head {set rev $create_branch_head}
        tracking {set rev $create_branch_trackinghead}
+       tag {set rev $create_branch_tag}
        expression {set rev $create_branch_revexp}
        }
-       if {[catch {set cmt [exec git rev-parse --verify "${rev}^0"]}]} {
+       if {[catch {set cmt [git rev-parse --verify "${rev}^0"]}]} {
                tk_messageBox \
                        -icon error \
                        -type ok \
@@ -1964,6 +2040,8 @@ trace add variable create_branch_head write \
        [list radio_selector create_branch_revtype head]
 trace add variable create_branch_trackinghead write \
        [list radio_selector create_branch_revtype tracking]
+trace add variable create_branch_tag write \
+       [list radio_selector create_branch_revtype tag]
 
 trace add variable delete_branch_head write \
        [list radio_selector delete_branch_checktype head]
@@ -1975,6 +2053,7 @@ proc do_create_branch {} {
        global create_branch_checkout create_branch_revtype
        global create_branch_head create_branch_trackinghead
        global create_branch_name create_branch_revexp
+       global create_branch_tag
 
        set w .branch_editor
        toplevel $w
@@ -2038,6 +2117,19 @@ proc do_create_branch {} {
                        $all_trackings
                grid $w.from.tracking_r $w.from.tracking_m -sticky w
        }
+       set all_tags [load_all_tags]
+       if {$all_tags ne {}} {
+               set create_branch_tag [lindex $all_tags 0]
+               radiobutton $w.from.tag_r \
+                       -text {Tag:} \
+                       -value tag \
+                       -variable create_branch_revtype \
+                       -font font_ui
+               eval tk_optionMenu $w.from.tag_m \
+                       create_branch_tag \
+                       $all_tags
+               grid $w.from.tag_r $w.from.tag_m -sticky w
+       }
        radiobutton $w.from.exp_r \
                -text {Revision Expression:} \
                -value expression \
@@ -2100,7 +2192,7 @@ proc do_delete_branch_action {w} {
        }
        if {$check_rev eq {:none}} {
                set check_cmt {}
-       } elseif {[catch {set check_cmt [exec git rev-parse --verify "${check_rev}^0"]}]} {
+       } elseif {[catch {set check_cmt [git rev-parse --verify "${check_rev}^0"]}]} {
                tk_messageBox \
                        -icon error \
                        -type ok \
@@ -2114,10 +2206,10 @@ proc do_delete_branch_action {w} {
        set not_merged [list]
        foreach i [$w.list.l curselection] {
                set b [$w.list.l get $i]
-               if {[catch {set o [exec git rev-parse --verify $b]}]} continue
+               if {[catch {set o [git rev-parse --verify $b]}]} continue
                if {$check_cmt ne {}} {
                        if {$b eq $check_rev} continue
-                       if {[catch {set m [exec git merge-base $o $check_cmt]}]} continue
+                       if {[catch {set m [git merge-base $o $check_cmt]}]} continue
                        if {$o ne $m} {
                                lappend not_merged $b
                                continue
@@ -2155,7 +2247,7 @@ Delete the selected branches?}
        foreach i $to_delete {
                set b [lindex $i 0]
                set o [lindex $i 1]
-               if {[catch {exec git update-ref -d "refs/heads/$b" $o} err]} {
+               if {[catch {git update-ref -d "refs/heads/$b" $o} err]} {
                        append failed " - $b: $err\n"
                } else {
                        set x [lsearch -sorted -exact $all_heads $b]
@@ -2366,7 +2458,7 @@ Staying on branch '$current_branch'."
        #    here, it Just Works(tm).  If it doesn't we are in some really ugly
        #    state that is difficult to recover from within git-gui.
        #
-       if {[catch {exec git symbolic-ref HEAD "refs/heads/$new_branch"} err]} {
+       if {[catch {git symbolic-ref HEAD "refs/heads/$new_branch"} err]} {
                error_popup "Failed to set current branch.
 
 This working directory is only partially switched.
@@ -2876,14 +2968,16 @@ proc do_local_merge {} {
        pack $w.source -fill both -expand 1 -pady 5 -padx 5
 
        set cmd [list git for-each-ref]
-       lappend cmd {--format=%(objectname) %(refname)}
+       lappend cmd {--format=%(objectname) %(*objectname) %(refname)}
        lappend cmd refs/heads
        lappend cmd refs/remotes
+       lappend cmd refs/tags
        set fr_fd [open "| $cmd" r]
        fconfigure $fr_fd -translation binary
        while {[gets $fr_fd line] > 0} {
                set line [split $line { }]
-               set sha1([lindex $line 0]) [lindex $line 1]
+               set sha1([lindex $line 0]) [lindex $line 2]
+               set sha1([lindex $line 1]) [lindex $line 2]
        }
        close $fr_fd
 
@@ -2891,7 +2985,7 @@ proc do_local_merge {} {
        set fr_fd [open "| git rev-list --all --not HEAD"]
        while {[gets $fr_fd line] > 0} {
                if {[catch {set ref $sha1($line)}]} continue
-               regsub ^refs/(heads|remotes)/ $ref {} ref
+               regsub ^refs/(heads|remotes|tags)/ $ref {} ref
                lappend to_show $ref
        }
        close $fr_fd
@@ -2972,7 +3066,14 @@ proc new_browser {commit} {
        global next_browser_id cursor_ptr M1B
        global browser_commit browser_status browser_stack browser_path browser_busy
 
-       set w .browser[incr next_browser_id]
+       if {[winfo ismapped .]} {
+               set w .browser[incr next_browser_id]
+               set tl $w
+               toplevel $w
+       } else {
+               set w {}
+               set tl .
+       }
        set w_list $w.list.l
        set browser_commit($w_list) $commit
        set browser_status($w_list) {Starting...}
@@ -2980,7 +3081,6 @@ proc new_browser {commit} {
        set browser_path($w_list) $browser_commit($w_list):
        set browser_busy($w_list) 1
 
-       toplevel $w
        label $w.path -textvariable browser_path($w_list) \
                -anchor w \
                -justify left \
@@ -3030,8 +3130,8 @@ proc new_browser {commit} {
        bind $w_list <Left>            break
        bind $w_list <Right>           break
 
-       bind $w <Visibility> "focus $w"
-       bind $w <Destroy> "
+       bind $tl <Visibility> "focus $w"
+       bind $tl <Destroy> "
                array unset browser_buffer $w_list
                array unset browser_files $w_list
                array unset browser_status $w_list
@@ -3040,7 +3140,7 @@ proc new_browser {commit} {
                array unset browser_commit $w_list
                array unset browser_busy $w_list
        "
-       wm title $w "[appname] ([reponame]): File Browser"
+       wm title $tl "[appname] ([reponame]): File Browser"
        ls_tree $w_list $browser_commit($w_list) {}
 }
 
@@ -4161,7 +4261,7 @@ proc do_quit {} {
                        set rc_geometry {}
                }
                if {$cfg_geometry ne $rc_geometry} {
-                       catch {exec git config gui.geometry $cfg_geometry}
+                       catch {git config gui.geometry $cfg_geometry}
                }
        }
 
@@ -4380,6 +4480,61 @@ proc do_commit {} {
        commit_tree
 }
 
+proc do_credits {} {
+       global gitgui_credits
+
+       set w .credits_dialog
+
+       toplevel $w
+       wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
+
+       label $w.header -text {git-gui Contributors} -font font_uibold
+       pack $w.header -side top -fill x
+
+       frame $w.buttons
+       button $w.buttons.close -text {Close} \
+               -font font_ui \
+               -command [list destroy $w]
+       pack $w.buttons.close -side right
+       pack $w.buttons -side bottom -fill x -pady 10 -padx 10
+
+       frame $w.credits
+       text $w.credits.t \
+               -background [$w.header cget -background] \
+               -yscrollcommand [list $w.credits.sby set] \
+               -width 20 \
+               -height 10 \
+               -wrap none \
+               -borderwidth 1 \
+               -relief solid \
+               -padx 5 -pady 5 \
+               -font font_ui
+       scrollbar $w.credits.sby -command [list $w.credits.t yview]
+       pack $w.credits.sby -side right -fill y
+       pack $w.credits.t -fill both -expand 1
+       pack $w.credits -side top -fill both -expand 1 -padx 5 -pady 5
+
+       label $w.desc \
+               -text "All portions are copyrighted by their respective authors
+and are distributed under the GNU General Public License." \
+               -padx 5 -pady 5 \
+               -justify left \
+               -anchor w \
+               -borderwidth 1 \
+               -relief solid \
+               -font font_ui
+       pack $w.desc -side top -fill x -padx 5 -pady 5
+
+       $w.credits.t insert end "[string trim $gitgui_credits]\n"
+       $w.credits.t conf -state disabled
+       $w.credits.t see 1.0
+
+       bind $w <Visibility> "grab $w; focus $w"
+       bind $w <Key-Escape> [list destroy $w]
+       wm title $w [$w.header cget -text]
+       tkwait window $w
+}
+
 proc do_about {} {
        global appvers copyright
        global tcl_patchLevel tk_patchLevel
@@ -4396,11 +4551,15 @@ proc do_about {} {
        button $w.buttons.close -text {Close} \
                -font font_ui \
                -command [list destroy $w]
+       button $w.buttons.credits -text {Contributors} \
+               -font font_ui \
+               -command do_credits
+       pack $w.buttons.credits -side left
        pack $w.buttons.close -side right
        pack $w.buttons -side bottom -fill x -pady 10 -padx 10
 
        label $w.desc \
-               -text "[appname] - a commit creation tool for Git.
+               -text "git-gui - a graphical user interface for Git.
 $copyright" \
                -padx 5 -pady 5 \
                -justify left \
@@ -4411,8 +4570,8 @@ $copyright" \
        pack $w.desc -side top -fill x -padx 5 -pady 5
 
        set v {}
-       append v "[appname] version $appvers\n"
-       append v "[exec git version]\n"
+       append v "git-gui version $appvers\n"
+       append v "[git version]\n"
        append v "\n"
        if {$tcl_patchLevel eq $tk_patchLevel} {
                append v "Tcl/Tk version $tcl_patchLevel"
@@ -4471,7 +4630,7 @@ proc do_options {} {
        toplevel $w
        wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
 
-       label $w.header -text "[appname] Options" \
+       label $w.header -text "Options" \
                -font font_uibold
        pack $w.header -side top -fill x
 
@@ -4945,6 +5104,9 @@ enable_option branch
 enable_option transport
 
 switch -- $subcommand {
+--version -
+version -
+browser -
 blame {
        disable_option multicommit
        disable_option branch
@@ -5177,7 +5339,7 @@ if {[is_MacOSX]} {
        .mbar.apple add command -label "About [appname]" \
                -command do_about \
                -font font_ui
-       .mbar.apple add command -label "[appname] Options..." \
+       .mbar.apple add command -label "Options..." \
                -command do_options \
                -font font_ui
 } else {
@@ -5236,7 +5398,7 @@ set doc_path [file dirname [gitexec]]
 set doc_path [file join $doc_path Documentation index.html]
 
 if {[is_Cygwin]} {
-       set doc_path [exec cygpath --windows $doc_path]
+       set doc_path [exec cygpath --mixed $doc_path]
 }
 
 if {$browser eq {}} {
@@ -5280,6 +5442,20 @@ bind all <$M1B-Key-W> {destroy [winfo toplevel %W]}
 # -- Not a normal commit type invocation?  Do that instead!
 #
 switch -- $subcommand {
+--version -
+version {
+       puts "git-gui version $appvers"
+       exit
+}
+browser {
+       if {[llength $argv] != 1} {
+               puts stderr "usage: $argv0 browser commit"
+               exit 1
+       }
+       set current_branch [lindex $argv 0]
+       new_browser $current_branch
+       return
+}
 blame {
        if {[llength $argv] != 2} {
                puts stderr "usage: $argv0 blame commit path"
@@ -5302,7 +5478,7 @@ gui {
        # fall through to setup UI for commits
 }
 default {
-       puts stderr "usage: $argv0 \[{blame|citool}\]"
+       puts stderr "usage: $argv0 \[{blame|browser|citool}\]"
        exit 1
 }
 }
@@ -5552,9 +5728,6 @@ bind_button3 $ui_comm "tk_popup $ctxm %X %Y"
 
 # -- Diff Header
 #
-set current_diff_path {}
-set current_diff_side {}
-set diff_actions [list]
 proc trace_current_diff_path {varname args} {
        global current_diff_path diff_actions file_states
        if {$current_diff_path eq {}} {
@@ -5747,7 +5920,6 @@ unset ui_diff_applyhunk
 
 # -- Status Bar
 #
-set ui_status_value {Initializing...}
 label .status -textvariable ui_status_value \
        -anchor w \
        -justify left \
@@ -5821,15 +5993,6 @@ unset i
 set file_lists($ui_index) [list]
 set file_lists($ui_workdir) [list]
 
-set HEAD {}
-set PARENT {}
-set MERGE_HEAD [list]
-set commit_type {}
-set empty_tree {}
-set current_branch {}
-set current_diff_path {}
-set selected_commit_type new
-
 wm title . "[appname] ([file normalize [file dirname [gitdir]]])"
 focus -force $ui_comm
 
@@ -5904,7 +6067,7 @@ if {[is_enabled transport]} {
 if {[is_enabled multicommit]} {
        set object_limit 2000
        if {[is_Windows]} {set object_limit 200}
-       regexp {^([0-9]+) objects,} [exec git count-objects] _junk objects_current
+       regexp {^([0-9]+) objects,} [git count-objects] _junk objects_current
        if {$objects_current >= $object_limit} {
                if {[ask_popup \
                        "This repository currently has $objects_current loose objects.