Tuesday, September 08, 2009

Git (and Folder compare with Git with WinMerge)

[Update] there's a new post with instructions for configuring git at: http://pydev.blogspot.com/2011/02/git-on-command-line.html

In case it was missed, Pydev is now on Git :)

I'm finding it the hard way that unfortunately its eclipse integration is still not ready for prime time -- it's missing some basic things such as a synchronize view, and I've had some bugs for it to mark the changed files in the package explorer (so, I'm waiting until it matures a bit to give it another try).

In the meanwhile, I'm using the command line (with the msysgit bash).

The thing I missed most was the synchronize view. A part of my modus operandi is making a review of all the changes before doing a commit -- and editing some things there, so, based on this link, I've created a script -- which I called gitdd -- that will create a directory structure with the HEAD and links to the changed files so that one can change those files in a diff viewer (in this case, WinMerge).

The script is below if anyone wants to use it (note that it must be run in the msysgit bash -- although it should probably work on Linux too, with another diff viewer)


#!/bin/sh -e

# usage: gitdd <path>
# Compares the current differences in winmerge with links to original files.
# Note that it must be executed at the root of the git repository.

SUBDIRECTORY_OK=1

O=".git-winmerge-tmp-$$"
V=HEAD
list="$O/list"
list_exist="$O/list_exist"
trap "rm -rf $O" 0
mkdir $O
mkdir $O/b

git diff $V --name-only -z $1 > $list

/d/bin/Python261/python.exe /c/Program\ Files/Git/bin/gitddpy.py $list $O/b/

cat $list | xargs -0 git archive --prefix=a/ $V | /d/bin/bin-1.0/tar.exe xf - -C $O

/d/bin/WinMerge/WinMergeU.exe //r //u //wr //dl WorkingCopy $O/b $O/a


[Update]
I wanted to create links to the files (so that I could edit them on WinMerge and have the original changed), so, I ended up creating a gitddpy.py to create the link (not sure why git prompt was crashing when using the shell for that -- so, this was the solution that worked for me).

The gitddpy.py contents are:


import sys
print sys.argv

f = file(sys.argv[1])
contents = f.read()
import subprocess
import os.path
for line in contents.split('\0'):
    if os.path.exists(line):
        subprocess.call(['cp', line, '--parents', '-l',
        '--target-directory='+sys.argv[2]], shell=True)
f.close()



[Update]
Configuring Git with the following:

git config format.pretty "%h %ct %ad %Cgreen%aN%Creset %s"
git config log.date short

The commands I use most (using the msysgit Bash) are:

git status
git commit -a -m "Message"
git push origin master
git checkout <path>
git log -n 6 --format="%ct %Cgreen%aN%Creset %s"
git commit --amend (change last commit message)

And some of the commands I had to discover how to use in the msysgit bash are:

Alt+Space+E+K: mark contents for copy
Insert: paste contents
Alt+Back: erase until whitespace

The last thing worth mentioning is that the Pydev releases don't have such a nice unique id as the one that was available with subversion anymore, and it now contains the commit time (%ct in the log format). It's a bit annoying that it's such a big number, but I believe that the other choices were worse (the hash would seem totally random for someone seeing it, and basing it on the number of commits wouldn't work with history rewriting).

To sum things up: yes, I know that not being able to do everything in Eclipse sucks a bit, but hopefully the Git tools for Eclipse will catch up soon -- I'm hoping that having the history offline and not having to worry about renames, as well as the whole idea of decentralized versioning systems pays for this nuisance for now (and I'm certain that when the Eclipse plugin for Git catches up it'll be much better).

4 comments:

lig said...

Great news!

I agree that egit is not quite ready, but i've found it pretty usefull to view current tree state, just for information.

Another one: it is much more simplier to use git on Linux, just give it a try.

I use git from commandline and Meld for merging in case of conflicts.

Keep up the good work!

Anonymous said...

How is using git commandline on linux simpler than using git commandline on windows? The commands are exactly the same, so your claim makes no sense at all.

Fabio Zadrozny said...

I have to agree that on windows some things just don't work as expected...

The fact is that when someone wants to do some things that are a bit more complex, not having the linux shell makes a difference.

And I've had a few cases where it just crashed on me when using the shell from msysgit -- which I worked around invoking a python shell and doing things from there (although I think most things are working properly for the basic operations)

Caleb said...

Many thanks for your scripts! Here is a version of the shell script that doesn't require python.

#####################

#!/bin/sh

# usage: gitdd
# Compares the current differences in winmerge with links to original files.
# Note that it must be executed at the root of the git repository.

SUBDIRECTORY_OK=1

O=".git-winmerge-tmp-$$"
V=HEAD
list="$O/list"
list_exist="$O/list_exist"
# Delete everything created here on exit
trap "rm -rf $O" 0
mkdir $O
mkdir $O/WORKINGCOPY
# Dump
git diff $V --name-only -z $1 > $list
# Create links to changed files inside temp folder
# (changes made to these links will be made to originals)
for i in `cat $list | xargs -0`; do
PPATH=`dirname $i`
mkdir -p $O/WORKINGCOPY/$PPATH
ln $(pwd)/$i $(pwd)/$O/WORKINGCOPY/$i
done
# Copy HEAD versions of changed files to temp folder
cat $list | xargs -0 git archive --prefix=HEAD/ $V | tar xf - -C $O
# Execute winmerge which must be on the system path
WinMergeU.exe //r //u //wr //dl WORKINGCOPY //dr HEAD $O/WORKINGCOPY $O/HEAD