Git development
 help / color / mirror / Atom feed
* gitk changing line color for no reason after merge
From: Pavel Roskin @ 2006-02-02 17:21 UTC (permalink / raw)
  To: Paul Mackerras, git

Hello, Paul!

I have noticed that gitk changes the line color at a commit following a
merge (i.e. a commit with many parents).  I made this screenshot to
demonstrate the problem:

http://red-bean.com/proski/gitk/gitk.png

If you follow the leftmost line, you'll see how green becomes red, gray
becomes brown and red becomes blue.

I think it would be much better if line colors only change at
non-trivial nodes, i.e. those with more than one child or parent.

The fix is trivial:

diff --git a/gitk b/gitk
index f12b3ce..14ff570 100755
--- a/gitk
+++ b/gitk
@@ -770,7 +770,7 @@ proc assigncolor {id} {
 
     if [info exists colormap($id)] return
     set ncolors [llength $colors]
-    if {$nparents($id) <= 1 && $nchildren($id) == 1} {
+    if {$nchildren($id) == 1} {
 	set child [lindex $children($id) 0]
 	if {[info exists colormap($child)]
 	    && $nparents($child) == 1} {


I checked the history of gitk and could trace this code back to the
first version of gitk in the git repository.  Maybe it was intended this
way, but I think it would be better to fix it.

-- 
Regards,
Pavel Roskin

^ permalink raw reply related

* [PATCH 1/2] Provide a more meaningful initial "From " line when using --compose in git-send-email.
From: Ryan Anderson @ 2006-02-02 16:56 UTC (permalink / raw)
  To: git; +Cc: Ryan Anderson
In-Reply-To: <11388993661745-git-send-email-ryan@michonline.com>

git-send-email, when used with --compose, provided the user with a mbox-format
file to edit.  Some users, however, were confused by the leading, blank, "From
" line, so this change puts the value that will appear on the From: line of the
actual email on this line, along with a note that the line is ignored.

Signed-off-by: Ryan Anderson <ryan@michonline.com>

---

 git-send-email.perl |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

c6b0c22e482aa6fe314e4be077d705c98fee7bf2
diff --git a/git-send-email.perl b/git-send-email.perl
index ec1428d..51b7513 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -125,7 +125,7 @@ if ($compose) {
 	# effort to have it be unique
 	open(C,">",$compose_filename)
 		or die "Failed to open for writing $compose_filename: $!";
-	print C "From \n";
+	print C "From $from # This line is ignored.\n";
 	printf C "Subject: %s\n\n", $initial_subject;
 	printf C <<EOT;
 GIT: Please enter your email below.
-- 
1.1.4.g3dcbd

^ permalink raw reply related

* [PATCH 0/2] Small updates to git-send-email
From: Ryan Anderson @ 2006-02-02 16:56 UTC (permalink / raw)
  To: git

These updates fix some usability issues raised by Octavian in #git.

Thanks for the feedback!

-- 
Ryan Anderson
  sometimes Pug Majere

^ permalink raw reply

* [PATCH 2/2] git-send-email: Add --quiet to reduce some of the chatter when sending emails.
From: Ryan Anderson @ 2006-02-02 16:56 UTC (permalink / raw)
  To: git; +Cc: Ryan Anderson
In-Reply-To: <11388993663675-git-send-email-ryan@michonline.com>

Signed-off-by: Ryan Anderson <ryan@michonline.com>

---

 git-send-email.perl |    9 ++++++---
 1 files changed, 6 insertions(+), 3 deletions(-)

3dcbd6298dc6fb4a903404cb9c47e3690bf2e01a
diff --git a/git-send-email.perl b/git-send-email.perl
index 51b7513..ca1fa37 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -34,7 +34,7 @@ my $compose_filename = ".msg.$$";
 my (@to,@cc,$initial_reply_to,$initial_subject,@files,$from,$compose);
 
 # Behavior modification variables
-my ($chain_reply_to, $smtp_server) = (1, "localhost");
+my ($chain_reply_to, $smtp_server, $quiet) = (1, "localhost", 0);
 
 # Example reply to:
 #$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
@@ -51,6 +51,7 @@ my $rc = GetOptions("from=s" => \$from,
 		    "chain-reply-to!" => \$chain_reply_to,
 		    "smtp-server=s" => \$smtp_server,
 		    "compose" => \$compose,
+		    "quiet" => \$quiet,
 	 );
 
 # Now, let's fill any that aren't set in with defaults:
@@ -267,8 +268,10 @@ sub send_message
 
 	sendmail(%mail) or die $Mail::Sendmail::error;
 
-	print "OK. Log says:\n", $Mail::Sendmail::log;
-	print "\n\n"
+	unless ($quiet) {
+		print "OK. Log says:\n", $Mail::Sendmail::log;
+		print "\n\n"
+	}
 }
 
 
-- 
1.1.4.g3dcbd

^ permalink raw reply related

* Re: Two ideas for improving git's user interface
From: Carl Baldwin @ 2006-02-02 16:30 UTC (permalink / raw)
  To: Carl Worth; +Cc: Linus Torvalds, Junio C Hamano, Nicolas Pitre, git
In-Reply-To: <87lkwupsbr.wl%cworth@cworth.org>

On Wed, Feb 01, 2006 at 03:33:44PM -0800, Carl Worth wrote:
> 	Is it ever useful (reasonable, desirable) to commit file
> 	contents that differ from the contents of the working
> 	directory?

What _is_ useful about the status quo is the ability to make some minor
change, update that change to the index when I've decided that it is a
good change and then use git diff to see what I've incrementally changed
in the same file since that update.  That way new incremental changes
can be viewed independantly of the change I've already decided was good.

> What I would love to have is the ability to pass the same arguments to
> git diff to get a preview of what any get commit would do. For
> example, something like:
> 
> 	git diff		# would be a preview of:
> 	git commit

'git diff --cached' does this.

> 	git diff -a		# would be a preview of:
> 	git commit -a

'git diff HEAD' does this.

> 	git diff fileA fileB	# would be a preview of:
> 	git commit fileA fileB

Paths can be specified in conjunction with the above commands.

Yes, these are idioms specific to git and are not immediately intuitive
to the new user.  However, if the user has access to a good tutorial
that walks through these scenerios its not so bad.

Carl

-- 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Carl Baldwin                        RADCAD (R&D CAD)
 Hewlett Packard Company
 MS 88                               work: 970 898-1523
 3404 E. Harmony Rd.                 work: Carl.N.Baldwin@hp.com
 Fort Collins, CO 80525              home: Carl@ecBaldwin.net
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

^ permalink raw reply

* Re: gitview 0.3
From: Aneesh Kumar @ 2006-02-02 16:03 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vzmlauw35.fsf@assigned-by-dhcp.cox.net>

[-- Attachment #1: Type: text/plain, Size: 2780 bytes --]

On 2/2/06, Junio C Hamano <junkio@cox.net> wrote:
> Nice work for 0.low-number version.
>
> On my notebook, I felt really miserable to see that the middle
> band taking so much space to show rev committer timestamp and
> parents.  The bottom window starts with the same information
> repeated (worse, with unreadable timestamp format) and I had to
> scroll all the way down to view the rest of the commit message.

I have rearranged the default with respect these frames. Attaching the
code below. Let me know if it is ok.


>
> If you absolutely want the middle band, maybe instead of showing
> object names in "Parents" "Children" part, you can show the
> one-line commit logs from them there, and pop-up the object
> names along with the rest of commit log message as mouse hovers
> over.
>
> I missed "this commit is branch head of X" and "this commit is
> tagged with T" markers gitk has.
>

I am planning to add this. I am yet to learn fully how to use the
cairo API. gitview was partly my attempt to learn pygtk.


> Needs a bit more compact layout to be useful for me.  In short,
> gitk's display does everything I want it to show in a compact
> enough way and I think there is no reason not to imitate it.
>

One thing i didn't like with gitk was the looks. And the diff window
was so shaded i had to put real effort to read the contents. May be i
didn't had necessary fonts. I don't know


> Do colors of nodes have any significance?  I couldn't tell from
> the UI (and I tried to figure it out without reading code --
> otherwise I cannot tell if the choice of colors is intuitive).
>

One parent of the child follows the same colour. It in a way let one
figure out at what point branch happened and at what point they merged
back.


> It might match more people's expectation if --with-diff were the
> default.
>

This is done. I am attaching the full code below. Can you get the
gitview added git repository so that next time onwards i need to send
only the diff.

> This patch might make merges easier to read.
>
> -- >8 --
> [PATCH] Use "diff-tree -c" to display merges a bit more readably.
>
> --- a/gitview   2006-02-01 21:16:43.000000000 -0800
> +++ b/gitview   2006-02-01 21:46:24.000000000 -0800
> @@ -305,7 +305,7 @@
>                 return message
>
>         def diff_tree(self):
> -               fp = os.popen("git diff-tree --pretty -m -v -p " + " " + self.commit_sha1)
> +               fp = os.popen("git diff-tree --pretty -c -v -p " + " " + self.commit_sha1)
>                 diff = fp.read()
>                 fp.close()
>
>
>
>


I am using the --cc flag and if i don't have any message i get the
commit message only using git cat-file. I guess that is ok

-aneesh

[-- Attachment #2: gitview --]
[-- Type: application/octet-stream, Size: 24940 bytes --]

#! /usr/bin/env python

# 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
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

""" gitview
GUI browser for git repository 
This program is based on bzrk by Scott James Remnant <scott@ubuntu.com>
"""
__author__    = "Aneesh Kumar K.V <aneesh.kumar@gmail.com>"


import sys
import os
import gtk
import pygtk
import pango
import re
import time
import gobject
import cairo
import math
import string

try:
    import gtksourceview
    have_gtksourceview = True
except ImportError:
    have_gtksourceview = False
    print "Running without gtksourceview module"


def list_to_string(args, skip):
	count = len(args)
	i = skip
	str_arg=" "
	while (i < count ):
		str_arg = str_arg + args[i]
		str_arg = str_arg + " "
		i = i+1

	return str_arg


class CellRendererGraph(gtk.GenericCellRenderer):
	"""Cell renderer for directed graph.

	This module contains the implementation of a custom GtkCellRenderer that
	draws part of the directed graph based on the lines suggested by the code
	in graph.py.

	Because we're shiny, we use Cairo to do this, and because we're naughty
	we cheat and draw over the bits of the TreeViewColumn that are supposed to
	just be for the background.

	Properties:
	node              (column, colour) tuple to draw revision node,
	in_lines          (start, end, colour) tuple list to draw inward lines,
	out_lines         (start, end, colour) tuple list to draw outward lines.
	"""

	__gproperties__ = {
	"node":         ( gobject.TYPE_PYOBJECT, "node",
			  "revision node instruction",
			  gobject.PARAM_WRITABLE
			),
	"in-lines":     ( gobject.TYPE_PYOBJECT, "in-lines",
			  "instructions to draw lines into the cell",
			  gobject.PARAM_WRITABLE
			),
	"out-lines":    ( gobject.TYPE_PYOBJECT, "out-lines",
			  "instructions to draw lines out of the cell",
			  gobject.PARAM_WRITABLE
			),
	}

	def do_set_property(self, property, value):
		"""Set properties from GObject properties."""
		if property.name == "node":
			self.node = value
		elif property.name == "in-lines":
			self.in_lines = value
		elif property.name == "out-lines":
			self.out_lines = value
		else:
			raise AttributeError, "no such property: '%s'" % property.name

	def box_size(self, widget):
		"""Calculate box size based on widget's font.

		Cache this as it's probably expensive to get.  It ensures that we
		draw the graph at least as large as the text.
		"""
		try:
			return self._box_size
		except AttributeError:
			pango_ctx = widget.get_pango_context()
			font_desc = widget.get_style().font_desc
			metrics = pango_ctx.get_metrics(font_desc)

			ascent = pango.PIXELS(metrics.get_ascent())
			descent = pango.PIXELS(metrics.get_descent())

			self._box_size = ascent + descent + 6
			return self._box_size

	def set_colour(self, ctx, colour, bg, fg):
		"""Set the context source colour.

		Picks a distinct colour based on an internal wheel; the bg
		parameter provides the value that should be assigned to the 'zero'
		colours and the fg parameter provides the multiplier that should be
		applied to the foreground colours.
		"""
		colours = [
		    ( 1.0, 0.0, 0.0 ),
		    ( 1.0, 1.0, 0.0 ),
		    ( 0.0, 1.0, 0.0 ),
		    ( 0.0, 1.0, 1.0 ),
		    ( 0.0, 0.0, 1.0 ),
		    ( 1.0, 0.0, 1.0 ),
		    ]

		colour %= len(colours)
		red   = (colours[colour][0] * fg) or bg
		green = (colours[colour][1] * fg) or bg
		blue  = (colours[colour][2] * fg) or bg

		ctx.set_source_rgb(red, green, blue)

	def on_get_size(self, widget, cell_area):
		"""Return the size we need for this cell.

		Each cell is drawn individually and is only as wide as it needs
		to be, we let the TreeViewColumn take care of making them all
		line up.
		"""
		box_size = self.box_size(widget)

		cols = self.node[0]
		for start, end, colour in self.in_lines + self.out_lines:
			cols = max(cols, start, end)

		width = box_size * (cols + 1)
		height = box_size

		# FIXME I have no idea how to use cell_area properly
		return (0, 0, width, height)

	def on_render(self, window, widget, bg_area, cell_area, exp_area, flags):
		"""Render an individual cell.

		Draws the cell contents using cairo, taking care to clip what we
		do to within the background area so we don't draw over other cells.
		Note that we're a bit naughty there and should really be drawing
		in the cell_area (or even the exposed area), but we explicitly don't
		want any gutter.

		We try and be a little clever, if the line we need to draw is going
		to cross other columns we actually draw it as in the .---' style
		instead of a pure diagonal ... this reduces confusion by an
		incredible amount.
		"""
		ctx = window.cairo_create()
		ctx.rectangle(bg_area.x, bg_area.y, bg_area.width, bg_area.height)
		ctx.clip()

		box_size = self.box_size(widget)

		ctx.set_line_width(box_size / 8)
		ctx.set_line_cap(cairo.LINE_CAP_SQUARE)

		# Draw lines into the cell
		for start, end, colour in self.in_lines:
			ctx.move_to(cell_area.x + box_size * start + box_size / 2,
					bg_area.y - bg_area.height / 2)

			if start - end > 1:
				ctx.line_to(cell_area.x + box_size * start, bg_area.y)
				ctx.line_to(cell_area.x + box_size * end + box_size, bg_area.y)
			elif start - end < -1:
				ctx.line_to(cell_area.x + box_size * start + box_size,
						bg_area.y)
				ctx.line_to(cell_area.x + box_size * end, bg_area.y)

		    	ctx.line_to(cell_area.x + box_size * end + box_size / 2,
					bg_area.y + bg_area.height / 2)

			self.set_colour(ctx, colour, 0.0, 0.65)
			ctx.stroke()

		# Draw lines out of the cell
		for start, end, colour in self.out_lines:
			ctx.move_to(cell_area.x + box_size * start + box_size / 2,
					bg_area.y + bg_area.height / 2)

			if start - end > 1:
				ctx.line_to(cell_area.x + box_size * start,
						bg_area.y + bg_area.height)
				ctx.line_to(cell_area.x + box_size * end + box_size,
						bg_area.y + bg_area.height)
			elif start - end < -1:
				ctx.line_to(cell_area.x + box_size * start + box_size,
						bg_area.y + bg_area.height)
				ctx.line_to(cell_area.x + box_size * end,
						bg_area.y + bg_area.height)

			ctx.line_to(cell_area.x + box_size * end + box_size / 2,
					bg_area.y + bg_area.height / 2 + bg_area.height)

			self.set_colour(ctx, colour, 0.0, 0.65)
			ctx.stroke()

		# Draw the revision node in the right column
		(column, colour) = self.node
		ctx.arc(cell_area.x + box_size * column + box_size / 2,
				cell_area.y + cell_area.height / 2,
				box_size / 4, 0, 2 * math.pi)

		self.set_colour(ctx, colour, 0.0, 0.5)
		ctx.stroke_preserve()

		self.set_colour(ctx, colour, 0.5, 1.0)
		ctx.fill()

class Commit:
	""" This represent a commit object obtained after parsing the git-rev-list 
	output """

	children_sha1 = {}

	def __init__(self, commit_lines):
		self.message 		= ""
		self.author		= ""
		self.date 		= ""
		self.committer 		= ""
		self.commit_date 	= ""
		self.commit_sha1	= ""
		self.parent_sha1	= [ ]
		self.parse_commit(commit_lines)


	def parse_commit(self, commit_lines):

		# First line is the sha1 lines
		line = string.strip(commit_lines[0])
		sha1 = re.split(" ", line)
		self.commit_sha1 = sha1[0]
		self.parent_sha1 = sha1[1:]

		#build the child list
		for parent_id in self.parent_sha1:
			try:
				Commit.children_sha1[parent_id].append(self.commit_sha1)
			except KeyError:
				Commit.children_sha1[parent_id] = [self.commit_sha1]

		# IF we don't have parent
		if (len(self.parent_sha1) == 0):
			self.parent_sha1 = [0]

		for line in commit_lines[1:]:
			m = re.match("^ ", line)
			if (m != None):
				# First line of the commit message used for short log
				if self.message == "":
					self.message = string.strip(line)
				continue

			m = re.match("tree", line)
			if (m != None):
				continue

			m = re.match("parent", line)
			if (m != None):
				continue


			m = re.match("author", line)
			if (m  != None ):
				patch_author = re.split(" ", line)	
				self.author = list_to_string(patch_author[1:-2], 0)
				self.date = time.strftime("%Y-%m-%d %H:%M:%S",
						time.gmtime(float(patch_author[-2])))
				continue

			m = re.match("committer", line)
			if (m  != None ):
				patch_committer = re.split(" ", line)	
				self.committer = list_to_string(patch_committer[1:-2], 0)
				self.commit_date = time.strftime("%Y-%m-%d %H:%M:%S",
						time.gmtime(float(patch_committer[-2])))
				continue

	def get_message(self, with_diff=0):
		if (with_diff == 1):
			message = self.diff_tree()
		else:
			fp = os.popen("git cat-file commit " + self.commit_sha1)
			message = fp.read()
			fp.close()

		return message

	def diff_tree(self):
		fp = os.popen("git diff-tree --pretty --cc  -v -p " + " " + self.commit_sha1)
		diff = fp.read()
		fp.close()
		if (diff == ""):
			# After optimization in case of merge commits if don't
			# have any diffs. Just show the commit message
			diff = self.get_message(0)

		return diff

class DiffWindow:
	"""Diff window.
	This object represents and manages a single window containing the
	differences between two revisions on a branch.
	"""

	def __init__(self):
		self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
		self.window.set_border_width(0)
		self.window.set_title("Git repository browser diff window")

		# Use two thirds of the screen by default
		screen = self.window.get_screen()
		monitor = screen.get_monitor_geometry(0)
		width = int(monitor.width * 0.66)
		height = int(monitor.height * 0.66)
		self.window.set_default_size(width, height)

		self.construct()

	def construct(self):
		"""Construct the window contents."""
		hbox = gtk.HBox(spacing=6)
		hbox.set_border_width(12)
		self.window.add(hbox)
		hbox.show()

		scrollwin = gtk.ScrolledWindow()
		scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
		scrollwin.set_shadow_type(gtk.SHADOW_IN)
		hbox.pack_start(scrollwin, expand=True, fill=True)
		scrollwin.show()

		if have_gtksourceview:
			self.buffer = gtksourceview.SourceBuffer()
			slm = gtksourceview.SourceLanguagesManager()
			gsl = slm.get_language_from_mime_type("text/x-patch")
			self.buffer.set_highlight(True)
			self.buffer.set_language(gsl)
			sourceview = gtksourceview.SourceView(self.buffer)
		else:
			self.buffer = gtk.TextBuffer()
			sourceview = gtk.TextView(self.buffer)

		sourceview.set_editable(False)
		sourceview.modify_font(pango.FontDescription("Monospace"))
		scrollwin.add(sourceview)
		sourceview.show()


	def set_diff(self, commit_sha1, parent_sha1):
		"""Set the differences showed by this window.
		Compares the two trees and populates the window with the
		differences.
		"""
		# Diff with the first commit or the last commit shows nothing
		if (commit_sha1 == 0 or parent_sha1 == 0 ):
			return 

		fp = os.popen("git diff-tree -p " + parent_sha1 + " " + commit_sha1)
		self.buffer.set_text(fp.read())
		fp.close()
		self.window.show()


class GitView:
	""" This is the main class
	"""

	def __init__(self, with_diff=0):
		self.with_diff = with_diff
        	self.window =  	gtk.Window(gtk.WINDOW_TOPLEVEL)
        	self.window.set_border_width(0)
		self.window.set_title("Git repository browser")


        	# Use three-quarters of the screen by default
        	screen = self.window.get_screen()
        	monitor = screen.get_monitor_geometry(0)
        	width = int(monitor.width * 0.75)
        	height = int(monitor.height * 0.75)
        	self.window.set_default_size(width, height)

        	# FIXME AndyFitz!
        	icon = self.window.render_icon(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)
        	self.window.set_icon(icon)

        	self.accel_group = gtk.AccelGroup()
        	self.window.add_accel_group(self.accel_group)

        	self.construct()


	def construct(self):
		"""Construct the window contents."""
		paned = gtk.VPaned()
		paned.pack1(self.construct_top(), resize=False, shrink=True)
		paned.pack2(self.construct_bottom(), resize=False, shrink=True)
		self.window.add(paned)
		paned.show()

	def construct_top(self):
		"""Construct the top-half of the window."""
		vbox = gtk.VBox(spacing=6)
		vbox.set_border_width(12)
		vbox.show()

		scrollwin = gtk.ScrolledWindow()
		scrollwin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
		scrollwin.set_shadow_type(gtk.SHADOW_IN)
		vbox.pack_start(scrollwin, expand=True, fill=True)
		scrollwin.show()

		self.treeview = gtk.TreeView()
		self.treeview.set_rules_hint(True)
		self.treeview.set_search_column(4)
		self.treeview.connect("cursor-changed", self._treeview_cursor_cb)
		scrollwin.add(self.treeview)
		self.treeview.show()

		cell = CellRendererGraph()
		column = gtk.TreeViewColumn()
		column.set_resizable(False)
		column.pack_start(cell, expand=False)
		column.add_attribute(cell, "node", 1)
		column.add_attribute(cell, "in-lines", 2)
		column.add_attribute(cell, "out-lines", 3)
		self.treeview.append_column(column)

		cell = gtk.CellRendererText()
		cell.set_property("width-chars", 65)
		cell.set_property("ellipsize", pango.ELLIPSIZE_END)
		column = gtk.TreeViewColumn("Message")
		column.set_resizable(True)
		column.pack_start(cell, expand=True)
		column.add_attribute(cell, "text", 4)
		self.treeview.append_column(column)

		cell = gtk.CellRendererText()
		cell.set_property("width-chars", 40)
		cell.set_property("ellipsize", pango.ELLIPSIZE_END)
		column = gtk.TreeViewColumn("Author")
		column.set_resizable(True)
		column.pack_start(cell, expand=True)
		column.add_attribute(cell, "text", 5)
		self.treeview.append_column(column)

		cell = gtk.CellRendererText()
		cell.set_property("ellipsize", pango.ELLIPSIZE_END)
		column = gtk.TreeViewColumn("Date")
		column.set_resizable(True)
		column.pack_start(cell, expand=True)
		column.add_attribute(cell, "text", 6)
		self.treeview.append_column(column)

		return vbox


	def construct_bottom(self):
		"""Construct the bottom half of the window."""
		vbox = gtk.VBox(False, spacing=6)
		vbox.set_border_width(12)
		(width, height) = self.window.get_size()
		vbox.set_size_request(width, int(height / 2.5))
		vbox.show()

		self.table = gtk.Table(rows=4, columns=4)
		self.table.set_row_spacings(6)
		self.table.set_col_spacings(6)
		vbox.pack_start(self.table, expand=False, fill=True)
		self.table.show()

		align = gtk.Alignment(0.0, 0.5)
		label = gtk.Label()
		label.set_markup("<b>Revision:</b>")
		align.add(label)
		self.table.attach(align, 0, 1, 0, 1, gtk.FILL, gtk.FILL)
		label.show()
		align.show()

		align = gtk.Alignment(0.0, 0.5)
		self.revid_label = gtk.Label()
		self.revid_label.set_selectable(True)
		align.add(self.revid_label)
		self.table.attach(align, 1, 2, 0, 1, gtk.EXPAND | gtk.FILL, gtk.FILL)
		self.revid_label.show()
		align.show()

		align = gtk.Alignment(0.0, 0.5)
		label = gtk.Label()
		label.set_markup("<b>Committer:</b>")
		align.add(label)
		self.table.attach(align, 0, 1, 1, 2, gtk.FILL, gtk.FILL)
		label.show()
		align.show()

		align = gtk.Alignment(0.0, 0.5)
		self.committer_label = gtk.Label()
		self.committer_label.set_selectable(True)
		align.add(self.committer_label)
		self.table.attach(align, 1, 2, 1, 2, gtk.EXPAND | gtk.FILL, gtk.FILL)
		self.committer_label.show()
		align.show()

		align = gtk.Alignment(0.0, 0.5)
		label = gtk.Label()
		label.set_markup("<b>Timestamp:</b>")
		align.add(label)
		self.table.attach(align, 0, 1, 2, 3, gtk.FILL, gtk.FILL)
		label.show()
		align.show()

		align = gtk.Alignment(0.0, 0.5)
		self.timestamp_label = gtk.Label()
		self.timestamp_label.set_selectable(True)
		align.add(self.timestamp_label)
		self.table.attach(align, 1, 2, 2, 3, gtk.EXPAND | gtk.FILL, gtk.FILL)
		self.timestamp_label.show()
		align.show()

		align = gtk.Alignment(0.0, 0.5)
		label = gtk.Label()
		label.set_markup("<b>Parents:</b>")
		align.add(label)
		self.table.attach(align, 0, 1, 3, 4, gtk.FILL, gtk.FILL)
		label.show()
		align.show()
		self.parents_widgets = []

		align = gtk.Alignment(0.0, 0.5)
		label = gtk.Label()
		label.set_markup("<b>Children:</b>")
		align.add(label)
		self.table.attach(align, 2, 3, 3, 4, gtk.FILL, gtk.FILL)
		label.show()
		align.show()
		self.children_widgets = []

		scrollwin = gtk.ScrolledWindow()
		scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
		scrollwin.set_shadow_type(gtk.SHADOW_IN)
		vbox.pack_start(scrollwin, expand=True, fill=True)
		scrollwin.show()

		if have_gtksourceview:
			self.message_buffer = gtksourceview.SourceBuffer()
			slm = gtksourceview.SourceLanguagesManager()
			gsl = slm.get_language_from_mime_type("text/x-patch")
			self.message_buffer.set_highlight(True)
			self.message_buffer.set_language(gsl)
			sourceview = gtksourceview.SourceView(self.message_buffer)
		else:
			self.message_buffer = gtk.TextBuffer()
			sourceview = gtk.TextView(self.message_buffer)

		sourceview.set_editable(False)
		sourceview.modify_font(pango.FontDescription("Monospace"))
		scrollwin.add(sourceview)
		sourceview.show()

		return vbox

	def _treeview_cursor_cb(self, *args):
		"""Callback for when the treeview cursor changes."""
		(path, col) = self.treeview.get_cursor()
		commit = self.model[path][0]

		if commit.committer is not None:
			committer = commit.committer
			timestamp = commit.commit_date
			message   =  commit.get_message(self.with_diff)
			revid_label = commit.commit_sha1
		else:
    			committer = ""
    			timestamp = ""
    			message = ""
			revid_label = ""

		self.revid_label.set_text(revid_label)
		self.committer_label.set_text(committer)
		self.timestamp_label.set_text(timestamp)
		self.message_buffer.set_text(message)

		for widget in self.parents_widgets:
			self.table.remove(widget)

		self.parents_widgets = []
		self.table.resize(4 + len(commit.parent_sha1) - 1, 4)
		for idx, parent_id in enumerate(commit.parent_sha1):
			self.table.set_row_spacing(idx + 3, 0)

			align = gtk.Alignment(0.0, 0.0)
			self.parents_widgets.append(align)
			self.table.attach(align, 1, 2, idx + 3, idx + 4,
					gtk.EXPAND | gtk.FILL, gtk.FILL)
			align.show()

			hbox = gtk.HBox(False, 0)
			align.add(hbox)
			hbox.show()

			label = gtk.Label(parent_id)
			label.set_selectable(True)
			hbox.pack_start(label, expand=False, fill=True)
			label.show()

			image = gtk.Image()
			image.set_from_stock(gtk.STOCK_JUMP_TO, gtk.ICON_SIZE_MENU)
			image.show()

			button = gtk.Button()
			button.add(image)
			button.set_relief(gtk.RELIEF_NONE)
			button.connect("clicked", self._go_clicked_cb, parent_id)
			hbox.pack_start(button, expand=False, fill=True)
			button.show()

			image = gtk.Image()
			image.set_from_stock(gtk.STOCK_FIND, gtk.ICON_SIZE_MENU)
			image.show()

			button = gtk.Button()
			button.add(image)
			button.set_relief(gtk.RELIEF_NONE)
			button.set_sensitive(True)
			button.connect("clicked", self._show_clicked_cb,
					commit.commit_sha1, parent_id)
			hbox.pack_start(button, expand=False, fill=True)
			button.show()

		# Populate with child details
		for widget in self.children_widgets:
			self.table.remove(widget)

		self.children_widgets = []
		try:
			child_sha1 = Commit.children_sha1[commit.commit_sha1]
		except KeyError:
			# We don't have child
			child_sha1 = [ 0 ]

		if ( len(child_sha1) > len(commit.parent_sha1)):
			self.table.resize(4 + len(child_sha1) - 1, 4)

		for idx, child_id in enumerate(child_sha1):
			self.table.set_row_spacing(idx + 3, 0)

			align = gtk.Alignment(0.0, 0.0)
			self.children_widgets.append(align)
			self.table.attach(align, 3, 4, idx + 3, idx + 4,
					gtk.EXPAND | gtk.FILL, gtk.FILL)
			align.show()

			hbox = gtk.HBox(False, 0)
			align.add(hbox)
			hbox.show()

			label = gtk.Label(child_id)
			label.set_selectable(True)
			hbox.pack_start(label, expand=False, fill=True)
			label.show()

			image = gtk.Image()
			image.set_from_stock(gtk.STOCK_JUMP_TO, gtk.ICON_SIZE_MENU)
			image.show()

			button = gtk.Button()
			button.add(image)
			button.set_relief(gtk.RELIEF_NONE)
			button.connect("clicked", self._go_clicked_cb, child_id)
			hbox.pack_start(button, expand=False, fill=True)
			button.show()

			image = gtk.Image()
			image.set_from_stock(gtk.STOCK_FIND, gtk.ICON_SIZE_MENU)
			image.show()

			button = gtk.Button()
			button.add(image)
			button.set_relief(gtk.RELIEF_NONE)
			button.set_sensitive(True)
			button.connect("clicked", self._show_clicked_cb,
					child_id, commit.commit_sha1)
			hbox.pack_start(button, expand=False, fill=True)
			button.show()

	def _destroy_cb(self, widget):
		"""Callback for when a window we manage is destroyed."""
		self.quit()


	def quit(self):
		"""Stop the GTK+ main loop."""
		gtk.main_quit()

	def run(self, args):
		self.set_branch(args)
        	self.window.connect("destroy", self._destroy_cb)
		self.window.show()
		gtk.main()

	def set_branch(self, args):
		"""Fill in different windows with info from the reposiroty"""
		fp = os.popen("git rev-parse --sq --default HEAD " + list_to_string(args, 1))
		git_rev_list_cmd = fp.read()
		fp.close()
		fp = os.popen("git rev-list  --header --topo-order --parents " + git_rev_list_cmd)
		self.update_window(fp)

	def update_window(self, fp):
		commit_lines = []

		self.model = gtk.ListStore(gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT,
				gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, str, str, str)

		# used for cursor positioning 
		self.index = {}

		self.colours = {}
		self.nodepos = {}
		self.incomplete_line = {}

		index = 0
		last_colour = 0
		last_nodepos = -1
		out_line = []	
		input_line = fp.readline()
		while (input_line != ""):
			# The commit header ends with '\0'
			# This NULL is immediately followed by the sha1 of the 
			# next commit
			if (input_line[0] != '\0'):
				commit_lines.append(input_line)
				input_line = fp.readline()
				continue;

			commit = Commit(commit_lines)
			if (commit != None ):
				(out_line, last_colour, last_nodepos) = self.draw_graph(commit,
										index, out_line,
										last_colour,
										last_nodepos)
				self.index[commit.commit_sha1] = index
				index += 1

			# Skip the '\0
			commit_lines = []
			commit_lines.append(input_line[1:])
			input_line = fp.readline()

		fp.close()

		self.treeview.set_model(self.model)
		self.treeview.show()

	def draw_graph(self, commit, index, out_line, last_colour, last_nodepos):
		in_line=[]

		#   |   -> outline
		#   X
		#   |\  <- inline 

		# Reset nodepostion
		if (last_nodepos > 5):
			last_nodepos = 0

		# Add the incomplete lines of the last cell in this 
		for sha1 in self.incomplete_line.keys():
			if ( sha1 != commit.commit_sha1):
				for pos in self.incomplete_line[sha1]:
					in_line.append((pos, pos, self.colours[sha1]))
			else:
				del self.incomplete_line[sha1]

		try:
			colour = self.colours[commit.commit_sha1]
		except KeyError:
			last_colour +=1
			self.colours[commit.commit_sha1] = last_colour
			colour =  last_colour
		try:
			node_pos = self.nodepos[commit.commit_sha1]
		except KeyError:
			last_nodepos +=1
			self.nodepos[commit.commit_sha1] = last_nodepos
			node_pos = last_nodepos

		#The first parent always continue on the same line
		try:
			# check we alreay have the value
			tmp_node_pos = self.nodepos[commit.parent_sha1[0]]
		except KeyError:
			self.colours[commit.parent_sha1[0]] = colour
			self.nodepos[commit.parent_sha1[0]] = node_pos

		in_line.append((node_pos, self.nodepos[commit.parent_sha1[0]],
					self.colours[commit.parent_sha1[0]]))

		self.add_incomplete_line(commit.parent_sha1[0], index+1)

		if (len(commit.parent_sha1) > 1):
			for parent_id in commit.parent_sha1[1:]:
				try:
					tmp_node_pos = self.nodepos[parent_id]
				except KeyError:
					last_colour += 1;
					self.colours[parent_id] = last_colour
					last_nodepos +=1
					self.nodepos[parent_id] = last_nodepos

				in_line.append((node_pos, self.nodepos[parent_id],
							self.colours[parent_id]))
				self.add_incomplete_line(parent_id, index+1)

		node = (node_pos, colour) 

		self.model.append([commit, node, out_line, in_line,
				commit.message, commit.author, commit.date]) 

		return (in_line, last_colour, last_nodepos)

	def add_incomplete_line(self, sha1, index):
		try:
			self.incomplete_line[sha1].append(self.nodepos[sha1])
		except KeyError:
			self.incomplete_line[sha1] = [self.nodepos[sha1]]


	def _go_clicked_cb(self, widget, revid):
		"""Callback for when the go button for a parent is clicked."""
		try:
			self.treeview.set_cursor(self.index[revid])
		except KeyError:
			print "Revision %s not present in the list" % revid
			# revid == 0 is the parent of the first commit
			if (revid != 0 ):
				print "Try running gitview without any options"

		self.treeview.grab_focus()

	def _show_clicked_cb(self, widget,  commit_sha1, parent_sha1):
		"""Callback for when the show button for a parent is clicked."""
		window = DiffWindow()
		window.set_diff(commit_sha1, parent_sha1)
		self.treeview.grab_focus()

if __name__ == "__main__":
	without_diff = 0

	if (len(sys.argv) > 1 ):
		if (sys.argv[1] == "--without-diff"):
			without_diff = 1

	view = GitView( without_diff != 1)
	view.run(sys.argv[without_diff:])



^ permalink raw reply

* Re: [PATCH] git-svnimport.perl: fix for 'arg list too long...'
From: Sasha Khapyorsky @ 2006-02-02 14:26 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Matthias Urlichs
In-Reply-To: <7v3bj27kxe.fsf@assigned-by-dhcp.cox.net>

On 14:50 Wed 01 Feb     , Junio C Hamano wrote:
> 
> *1* I do not think this makes much of a difference but here is what
> I mean.
> 
> diff --git a/git-svnimport.perl b/git-svnimport.perl

Tested. Works good. I think your version is cleaner. Cosmetic comment btw:

> +		open my $F, "|-",
> +			qw(git-update-index --force-remove -z --stdin)
> +				or die $!;
> +		print $F "$_\0" for @u;
> +		close $F or die $!;

It is not critical, but this block may be under if(@u) {..} to prevent
"empty" git-update-index invocations.

Sasha.

^ permalink raw reply

* Re: Two ideas for improving git's user interface
From: Florian Weimer @ 2006-02-02 12:31 UTC (permalink / raw)
  To: git
In-Reply-To: <87lkwupsbr.wl%cworth@cworth.org>

* Carl Worth:

> Here's a fundamental question I have, (and thanks to Keith Packard for
> helping me to phrase it):
>
> 	Is it ever useful (reasonable, desirable) to commit file
> 	contents that differ from the contents of the working
> 	directory?

You mean like "darcs record"? 8-)

I think this is very useful functionality.  Granted, it interferes
with a rigorous developer-side regression test policy ("all changes
must have been built and passed the test suite").  But it encourages
things like fixing typos in comments you spot while editing a file for
other reasons.  And you can keep some ugly debugging code while
working on a series of changes.

^ permalink raw reply

* [PATCH] Fix date display
From: Jonas Fonseca @ 2006-02-02 12:21 UTC (permalink / raw)
  To: Aneesh Kumar; +Cc: git, junkio
In-Reply-To: <cc723f590602012033w41b49b2ao4423707702086739@mail.gmail.com>

Hello,

Here is a patch that uses the tz info for setting commit dates.

--- a/gitview	2006-02-02 12:29:05.000000000 +0100
+++ b/gitview	2006-02-02 12:28:24.000000000 +0100
@@ -31,6 +31,7 @@
     have_gtksourceview = False
     print "Running without gtksourceview module"
 
+re_ident = re.compile('(author|committer) (?P<ident>.*) (?P<epoch>\d+) (?P<tz>[+-]\d{4})')
 
 def list_to_string(args, skip):
 	count = len(args)
@@ -43,6 +44,16 @@
 
 	return str_arg
 
+def show_date(epoch, tz):
+	secs = float(epoch)
+	tzsecs = float(tz[1:3]) * 3600
+	tzsecs += float(tz[3:5]) * 60
+	if (tz[0] == "+"):
+		secs += tzsecs
+	else:
+		secs -= tzsecs
+	return time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(secs))
+
 
 class CellRendererGraph(gtk.GenericCellRenderer):
 	"""Cell renderer for directed graph.
@@ -277,22 +288,15 @@
 			if (m != None):
 				continue
 
-
-			m = re.match("author", line)
-			if (m  != None ):
-				patch_author = re.split(" ", line)	
-				self.author = list_to_string(patch_author[1:-2], 0)
-				self.date = time.strftime("%Y-%m-%d %H:%M:%S",
-						time.gmtime(float(patch_author[-2])))
-				continue
-
-			m = re.match("committer", line)
-			if (m  != None ):
-				patch_committer = re.split(" ", line)	
-				self.committer = list_to_string(patch_committer[1:-2], 0)
-				self.commit_date = time.strftime("%Y-%m-%d %H:%M:%S",
-						time.gmtime(float(patch_committer[-2])))
-				continue
+			m = re_ident.match(line)
+			if (m != None):
+				date = show_date(m.group('epoch'), m.group('tz'))
+				if m.group(1)[0] == 'a':
+					self.author = m.group('ident')
+					self.date = date
+				else:
+					self.committer = m.group('ident')
+					self.commit_date = date
 
 	def get_message(self, with_diff=0):
 		if (with_diff == 1):
-- 
Jonas Fonseca

^ permalink raw reply

* [PATCH 2/2] merge-recursive: Speed up commit graph construction
From: Fredrik Kuivinen @ 2006-02-02 11:43 UTC (permalink / raw)
  To: git; +Cc: junkio
In-Reply-To: <20060202113848.GA8103@c165.ib.student.liu.se>

Use __slots__ to speed up construction and decrease memory consumption
of the Commit objects.

Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>


---

 gitMergeCommon.py |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

23aa79d4e86761e049bc44b5106cd45355045174
diff --git a/gitMergeCommon.py b/gitMergeCommon.py
index ff6f58a..fdbf9e4 100644
--- a/gitMergeCommon.py
+++ b/gitMergeCommon.py
@@ -107,7 +107,10 @@ def isSha(obj):
     return (type(obj) is str and bool(shaRE.match(obj))) or \
            (type(obj) is int and obj >= 1)
 
-class Commit:
+class Commit(object):
+    __slots__ = ['parents', 'firstLineMsg', 'children', '_tree', 'sha',
+                 'virtual']
+
     def __init__(self, sha, parents, tree=None):
         self.parents = parents
         self.firstLineMsg = None
-- 
1.1.6.gc78e-dirty

^ permalink raw reply related

* [PATCH 1/2] merge-recursive: Make use of provided bases
From: Fredrik Kuivinen @ 2006-02-02 11:43 UTC (permalink / raw)
  To: git; +Cc: junkio
In-Reply-To: <20060202113848.GA8103@c165.ib.student.liu.se>

This makes some cases faster as we don't have to build the commit graph.

Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>


---

 git-merge-recursive.py |   31 +++++++++++++++++++++----------
 1 files changed, 21 insertions(+), 10 deletions(-)

c78eacd112489b264df5d176df287f7ff5696948
diff --git a/git-merge-recursive.py b/git-merge-recursive.py
index b17c8e5..ce8a31f 100755
--- a/git-merge-recursive.py
+++ b/git-merge-recursive.py
@@ -45,11 +45,10 @@ cacheOnly = False
 # The entry point to the merge code
 # ---------------------------------
 
-def merge(h1, h2, branch1Name, branch2Name, graph, callDepth=0):
+def merge(h1, h2, branch1Name, branch2Name, graph, callDepth=0, ancestor=None):
     '''Merge the commits h1 and h2, return the resulting virtual
     commit object and a flag indicating the cleaness of the merge.'''
     assert(isinstance(h1, Commit) and isinstance(h2, Commit))
-    assert(isinstance(graph, Graph))
 
     global outputIndent
 
@@ -58,7 +57,11 @@ def merge(h1, h2, branch1Name, branch2Na
     output(h2)
     sys.stdout.flush()
 
-    ca = getCommonAncestors(graph, h1, h2)
+    if ancestor:
+        ca = [ancestor]
+    else:
+        assert(isinstance(graph, Graph))
+        ca = getCommonAncestors(graph, h1, h2)
     output('found', len(ca), 'common ancestor(s):')
     for x in ca:
         output(x)
@@ -86,7 +89,7 @@ def merge(h1, h2, branch1Name, branch2Na
     [shaRes, clean] = mergeTrees(h1.tree(), h2.tree(), mergedCA.tree(),
                                  branch1Name, branch2Name)
 
-    if clean or cacheOnly:
+    if graph and (clean or cacheOnly):
         res = Commit(None, [h1, h2], tree=shaRes)
         graph.addNode(res)
     else:
@@ -891,12 +894,11 @@ def usage():
 
 # main entry point as merge strategy module
 # The first parameters up to -- are merge bases, and the rest are heads.
-# This strategy module figures out merge bases itself, so we only
-# get heads.
 
 if len(sys.argv) < 4:
     usage()
 
+bases = []
 for nextArg in xrange(1, len(sys.argv)):
     if sys.argv[nextArg] == '--':
         if len(sys.argv) != nextArg + 3:
@@ -907,6 +909,8 @@ for nextArg in xrange(1, len(sys.argv)):
         except IndexError:
             usage()
         break
+    else:
+        bases.append(sys.argv[nextArg])
 
 print 'Merging', h1, 'with', h2
 
@@ -914,10 +918,17 @@ try:
     h1 = runProgram(['git-rev-parse', '--verify', h1 + '^0']).rstrip()
     h2 = runProgram(['git-rev-parse', '--verify', h2 + '^0']).rstrip()
 
-    graph = buildGraph([h1, h2])
-
-    [dummy, clean] = merge(graph.shaMap[h1], graph.shaMap[h2],
-                           firstBranch, secondBranch, graph)
+    if len(bases) == 1:
+        base = runProgram(['git-rev-parse', '--verify',
+                           bases[0] + '^0']).rstrip()
+        ancestor = Commit(base, None)
+        [dummy, clean] = merge(Commit(h1, None), Commit(h2, None),
+                               firstBranch, secondBranch, None, 0,
+                               ancestor)
+    else:
+        graph = buildGraph([h1, h2])
+        [dummy, clean] = merge(graph.shaMap[h1], graph.shaMap[h2],
+                               firstBranch, secondBranch, graph)
 
     print ''
 except:
-- 
1.1.6.gc78e-dirty

^ permalink raw reply related

* [PATCH 0/2] Make merge recursive faster in some cases
From: Fredrik Kuivinen @ 2006-02-02 11:38 UTC (permalink / raw)
  To: git; +Cc: junkio

The first patch teaches git-merge-recursive how to use the bases that
are supplied by the merge driver program in some cases. To be more
precise: if git-merge-recursive is supplied with a single base then
that one will be used, otherwise git-merge-recursive will compute the
bases on its own.

The second patch makes the commit graph construction more efficient.

- Fredrik

^ permalink raw reply

* Re: The merge from hell...
From: Junio C Hamano @ 2006-02-02 10:41 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Marco Costalba, Junio C Hamano, Git Mailing List, Paul Mackerras,
	Marco Costalba
In-Reply-To: <Pine.LNX.4.64.0602020027400.21884@g5.osdl.org>

Linus Torvalds <torvalds@osdl.org> writes:

> On Thu, 2 Feb 2006, Aneesh Kumar wrote:
>> 
>> Ok i tried using --cc. But then as per the man page if the
>> optimization makes the all the hunks disapper then commit log is not
>> show unless -m is used.
>
> Ahh. You're mis-using git-diff-tree.
>
> git-diff-tree will _never_ show the commit log if the diff ends up being 
> empty.

True, I should fix the documentation.

It _might_ make sense for certain users like gitk and gitview if
we had a single tool that gives --pretty and its diff even if
the diff is empty.  Having said that, the flag --cc -m is too
specific.  If some uses want to see the commit log even for an
empty diff, that flag should not be something only --cc honors.

^ permalink raw reply

* [PATCH] combine-diff: add safety check to --cc.
From: Junio C Hamano @ 2006-02-02  9:34 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Git Mailing List, Paul Mackerras, Marco Costalba, Aneesh Kumar,
	Len Brown
In-Reply-To: <7voe1qtbr5.fsf_-_@assigned-by-dhcp.cox.net>

The earlier change implemented "only two version" check but
without checking if the change rewrites from all the parents.
This implements a check to make sure that a change introduced
by the merge from all the parents is caught to be interesting.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 Junio C Hamano <junkio@cox.net> writes:

 >  Linus Torvalds <torvalds@osdl.org> writes:
 >
 >  > On Wed, 1 Feb 2006, Linus Torvalds wrote:
 >  >
 >  > Actually, I take that back.
 >
 >  I do not do that "result to match the final" check in this
 >  version yet.  I'll need to revisit it before placing this in
 >  the master, but I am going to bed.

 Well, I didn't ;-).

 combine-diff.c |   20 ++++++++++++++++++--
 1 files changed, 18 insertions(+), 2 deletions(-)

43fef6678c8e925307197fb705e499a023bba838
diff --git a/combine-diff.c b/combine-diff.c
index 45f1822..69e19ed 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -397,7 +397,23 @@ static int make_hunks(struct sline *slin
 		hunk_end = j;
 
 		/* [i..hunk_end) are interesting.  Now is it really
-		 * interesting?
+		 * interesting?  We check if there are only two versions
+		 * and the result matches one of them.  That is, we look
+		 * at:
+		 *   (+) line, which records lines added to which parents;
+		 *       this line appears in the result.
+		 *   (-) line, which records from what parents the line
+		 *       was removed; this line does not appear in the result.
+		 * then check the set of parents the result has difference
+		 * from, from all lines.  If there are lines that has
+		 * different set of parents that the result has differences
+		 * from, that means we have more than two versions.
+		 *
+		 * Even when we have only two versions, if the result does
+		 * not match any of the parents, the it should be considered
+		 * interesting.  In such a case, we would have all '+' line.
+		 * After passing the above "two versions" test, that would
+		 * appear as "the same set of parents" to be "all parents".
 		 */
 		same_diff = 0;
 		has_interesting = 0;
@@ -429,7 +445,7 @@ static int make_hunks(struct sline *slin
 			}
 		}
 
-		if (!has_interesting) {
+		if (!has_interesting && same_diff != all_mask) {
 			/* This hunk is not that interesting after all */
 			for (j = hunk_begin; j < hunk_end; j++)
 				sline[j].flag &= ~mark;
-- 
1.1.6.g2672

^ permalink raw reply related

* Re: [Census] So who uses git?
From: Alex Riesen @ 2006-02-02  9:12 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Martin Langhoff, Ray Lehtiniemi, Radoslaw Szkodzinski,
	Keith Packard, Junio C Hamano, cworth, Git Mailing List
In-Reply-To: <Pine.LNX.4.64.0602010815480.21884@g5.osdl.org>

On 2/1/06, Linus Torvalds <torvalds@osdl.org> wrote:
> > $ time git update-index --refresh
> >
> > real    0m21.500s
> > user    0m0.358s
> > sys     0m1.406s
> >
> > WinNT, NTFS, 13k files, hot cache.
>
> That's 25% less files than the Linux kernel, and I can do that operation
> in 0m0.062s (0.012s user, 0.048s system).

correction. It's 18k files, which is almost the same as 2.6.13-rc6. But these
files got *very* long names (the project poisoned by classical C++ education
and breaks windows' 255 chars limit on filename length from time to time).
Refresh index in 2.6.13 is actualy consistantly faster:

$ cd src/linux-2.6.13-rc6
$ time git update-index --refresh
real    0m1.344s
user    0m0.358s
sys     0m0.984s

> So WinNT/cygwin is about 2.5 _orders_of_maginitude_ slower here, or 340
> times slower.
>
> Now, I'm tempted to say that NT is a piece of sh*t, but the fact is, your
> CPU-times seem to indicate that most of it is IO (and the "real" cost is
> just 1.7 seconds, much of which is system time, which in turn itself is
> probably due to the IO costs too - so even that isn't comparable with
> the ).
>
> Which may mean that you simply don't have enough memory to cache the whole
> thing. Which may be NT sucking, of course ("we don't like to use more than
> 10% of memory for caches"), but it might also be a tunable (which is sucky
> in itself, of course), but finally, it might just be that you just don't
> have a ton of memory. I've got 2GB in my machines, although 1GB is plenty
> to cache the kernel.

I have 2Gb, the "System Cache" is around 1.5Gb, and this is PIV 3.2GHz.
There seem to be no tunables for any kind of system stuff
(savin' on support costs, do they?).
You'd be very hardpressed not to say that windows is a piece of sh*t.

The "benchmark: several times in a row:

$ time git update-index --refresh
real    0m1.766s
user    0m0.498s
sys     0m1.203s

$ time git update-index --refresh
real    0m1.766s
user    0m0.358s
sys     0m1.390s

$ time git update-index --refresh
real    0m1.781s
user    0m0.420s
sys     0m1.311s

$ time git update-index --refresh
real    0m1.875s
user    0m0.374s
sys     0m1.343s

$ time git update-index --refresh
real    0m1.766s
user    0m0.326s
sys     0m1.375s

It is always almost the same time. I don't think it's IO, looks more like
cache accesses. It is just that bad in this cygwin+win2k combination.
Besides, I don't trust "time <command>" on windows much: it returned
sys time 0 for git-update-index in a directory which was read before.
Yes, there was disk activity, I can hear it real good with that barrakuda.

^ permalink raw reply

* Re: The merge from hell...
From: Linus Torvalds @ 2006-02-02  8:44 UTC (permalink / raw)
  To: Aneesh Kumar
  Cc: Marco Costalba, Junio C Hamano, Git Mailing List, Paul Mackerras,
	Marco Costalba
In-Reply-To: <cc723f590602020007s43f89d10i4529d118ade7c764@mail.gmail.com>



On Thu, 2 Feb 2006, Aneesh Kumar wrote:
> 
> Ok i tried using --cc. But then as per the man page if the
> optimization makes the all the hunks disapper then commit log is not
> show unless -m is used.

Ahh. You're mis-using git-diff-tree.

git-diff-tree will _never_ show the commit log if the diff ends up being 
empty. That can actually happen even for a regular commit, because we had 
some early bugs that allowed them.

See commit 69d37960b578be0a69383bd71d06c1fcfb86e8b9, for example. Notice 
how

	git-diff-tree --pretty 69d37960

is entirely silent, even though 

	git log 69d37960

clearly shows that the commit exists. I screwed up a commit, and 
effectively applied an empty patch (this was before git-apply would 
notice, and consider it an error - something I fixed very soon 
afterwards ;^).

> Is there a way to get the commit log printed.

Yes. What you should do is to do

	git-rev-list --parents --pretty

which gives the revision _log_ in pretty format. 

The difference between "git-rev-list --pretty" and "git-diff-tree 
--pretty" is really exactly that "git-rev-list" lists every revision, 
while git-diff-tree only lists revisions that _differ_ in the trees.

This, btw, is also really the main difference between doing a "git log" 
and doing a "git whatchanged". A "git log" shows all revisions (and uses 
"git-rev-list --pretty"). While "git whatchanged" shows what _changed_ 
(and uses "git-diff-tree --pretty").

For a revision tool like gitview, you want to use "git-rev-list --pretty".

[ SIDE NOTE! Actually, there's another format that you may find easier to 
  parse automatically: "git-rev-list --header". It uses the raw format, 
  and adds a NUL character between each rev. That makes things like the 
  date etc trivial to parse, and it's also slightly easier to see the end 
  of a commit message vs just a normal end-of-line. 

  So "gitk", for example, really parses the output of

	git-rev-list --header --topo-order --parents

  to generate the revision list. The "--topo-order" part guarantees that 
  all children will always be shown before any parents. ]

Hope that clarifies the issue.

		Linus

^ permalink raw reply

* Re: The merge from hell...
From: Junio C Hamano @ 2006-02-02  8:27 UTC (permalink / raw)
  To: Aneesh Kumar; +Cc: git
In-Reply-To: <cc723f590602020007s43f89d10i4529d118ade7c764@mail.gmail.com>

Aneesh Kumar <aneesh.kumar@gmail.com> writes:

> Ok i tried using --cc. But then as per the man page if the
> optimization makes the all the hunks disapper then commit log is not
> show unless -m is used. Is there a way to get the commit log printed.

Yes, there is a way.  I need to fix a bug ;-).

This patch was done on top of the other two patches I sent
earlier tonight, but should apply on top of master even if you
have not applied the other two.

--

diff --git a/combine-diff.c b/combine-diff.c
index 44931b2..45f1822 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -675,6 +675,8 @@ int diff_tree_combined_merge(const unsig
 					       show_empty_merge))
 				header = NULL;
 		}
+		if (header)
+			puts(header);
 	}
 
 	/* Clean things up */

^ permalink raw reply related

* [PATCH] combine-diff: update --cc "uninteresting hunks" logic.
From: Junio C Hamano @ 2006-02-02  8:18 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Git Mailing List, Paul Mackerras, Marco Costalba, Aneesh Kumar,
	Len Brown
In-Reply-To: <Pine.LNX.4.64.0602020002110.21884@g5.osdl.org>

Earlier logic was discarding hunks that has difference from only
one parent or the same difference from all but one parent.  This
changes it to check if the differences on all lines are from the
same sets of parents.  This discards more uninteresting hunks
and seems to match expectations more naturally.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 Linus Torvalds <torvalds@osdl.org> writes:

 > On Wed, 1 Feb 2006, Linus Torvalds wrote:
 >> 
 >> I _think_ your version of the rule ("pluses and minuses in all the same 
 >> columns") ends up being exactly the same as my rule ("only two different 
 >> versions").
 >
 > Actually, I take that back.

 I do not do that "result to match the final" check in this
 version yet.  I'll need to revisit it before placing this in
 the master, but I am going to bed.

 combine-diff.c |  102 ++++++++++++++++++--------------------------------------
 1 files changed, 33 insertions(+), 69 deletions(-)

bcb331e2e87c2d7221751994b5ead4a79dd2a17b
diff --git a/combine-diff.c b/combine-diff.c
index 0cc18fe..44931b2 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -262,58 +262,6 @@ static int interesting(struct sline *sli
 	return ((sline->flag & all_mask) != all_mask || sline->lost_head);
 }
 
-static unsigned long line_common_diff(struct sline *sline, unsigned long all_mask)
-{
-	/*
-	 * Look at the line and see from which parents we have the
-	 * same difference.
-	 */
-
-	/* Lower bits of sline->flag records if the parent had this
-	 * line, so XOR with all_mask gives us on-bits for parents we
-	 * have differences with.
-	 */
-	unsigned long common_adds = (sline->flag ^ all_mask) & all_mask;
-	unsigned long common_removes = all_mask;
-
-	/* If all the parents have this line, that also counts as
-	 * having the same difference.
-	 */
-	if (!common_adds)
-		common_adds = all_mask;
-
-	if (sline->lost_head) {
-		/* Lost head list records the lines removed from
-		 * the parents, and parent_map records from which
-		 * parent the line was removed.
-		 */
-		struct lline *ll;
-		for (ll = sline->lost_head; ll; ll = ll->next) {
-			common_removes &= ll->parent_map;
-		}
-	}
-	return common_adds & common_removes;
-}
-
-static unsigned long line_all_diff(struct sline *sline, unsigned long all_mask)
-{
-	/*
-	 * Look at the line and see from which parents we have some difference.
-	 */
-	unsigned long different = (sline->flag ^ all_mask) & all_mask;
-	if (sline->lost_head) {
-		/* Lost head list records the lines removed from
-		 * the parents, and parent_map records from which
-		 * parent the line was removed.
-		 */
-		struct lline *ll;
-		for (ll = sline->lost_head; ll; ll = ll->next) {
-			different |= ll->parent_map;
-		}
-	}
-	return different;
-}
-
 static unsigned long adjust_hunk_tail(struct sline *sline,
 				      unsigned long all_mask,
 				      unsigned long hunk_begin,
@@ -417,8 +365,7 @@ static int make_hunks(struct sline *slin
 	i = 0;
 	while (i < cnt) {
 		unsigned long j, hunk_begin, hunk_end;
-		int same, diff;
-		unsigned long same_diff, all_diff;
+		unsigned long same_diff;
 		while (i < cnt && !(sline[i].flag & mark))
 			i++;
 		if (cnt <= i)
@@ -449,23 +396,40 @@ static int make_hunks(struct sline *slin
 		}
 		hunk_end = j;
 
-		/* [i..hunk_end) are interesting.  Now does it have
-		 * the same change with all but one parent?
+		/* [i..hunk_end) are interesting.  Now is it really
+		 * interesting?
 		 */
-		same_diff = all_mask;
-		all_diff = 0;
-		for (j = i; j < hunk_end; j++) {
-			same_diff &= line_common_diff(sline + j, all_mask);
-			all_diff |= line_all_diff(sline + j, all_mask);
-		}
-		diff = same = 0;
-		for (j = 0; j < num_parent; j++) {
-			if (same_diff & (1UL<<j))
-				same++;
-			if (all_diff & (1UL<<j))
-				diff++;
+		same_diff = 0;
+		has_interesting = 0;
+		for (j = i; j < hunk_end && !has_interesting; j++) {
+			unsigned long this_diff = ~sline[j].flag & all_mask;
+			struct lline *ll = sline[j].lost_head;
+			if (this_diff) {
+				/* This has some changes.  Is it the
+				 * same as others?
+				 */
+				if (!same_diff)
+					same_diff = this_diff;
+				else if (same_diff != this_diff) {
+					has_interesting = 1;
+					break;
+				}
+			}
+			while (ll && !has_interesting) {
+				/* Lost this line from these parents;
+				 * who are they?  Are they the same?
+				 */
+				this_diff = ll->parent_map;
+				if (!same_diff)
+					same_diff = this_diff;
+				else if (same_diff != this_diff) {
+					has_interesting = 1;
+				}
+				ll = ll->next;
+			}
 		}
-		if ((num_parent - 1 <= same) || (diff == 1)) {
+
+		if (!has_interesting) {
 			/* This hunk is not that interesting after all */
 			for (j = hunk_begin; j < hunk_end; j++)
 				sline[j].flag &= ~mark;
-- 
1.1.6.g2672

^ permalink raw reply related

* Re: The merge from hell...
From: Linus Torvalds @ 2006-02-02  8:08 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Git Mailing List, Paul Mackerras, Marco Costalba, Aneesh Kumar,
	Len Brown
In-Reply-To: <Pine.LNX.4.64.0602012353130.21884@g5.osdl.org>



On Wed, 1 Feb 2006, Linus Torvalds wrote:
> 
> I _think_ your version of the rule ("pluses and minuses in all the same 
> columns") ends up being exactly the same as my rule ("only two different 
> versions").

Actually, I take that back.

My version of the rule was not just that there were only two versions: the 
merge _result_ had to match one of the versions in one of the branches 
too.

That's important. It's important because you _can_ actually have a merge 
where both branches have the exact same content, but some evil merger 
ended up editing just the merge result.

So there are literally just two versions, but one of the versions _only_ 
exists in the merge result. Such a thing must always be considered a 
conflict, since basically the merge result is obviously "interesting".

That requirement can still be rewritten as a slight variation of your 
version, I think: "the pluses and minuses are all in the same columns, and 
the final column has to match one other column"

Maybe I'm not thinking clearly. Somebody else should double-check my 
thinking. My brain is tired, and I'm going to bed.

			Linus

^ permalink raw reply

* Re: The merge from hell...
From: Aneesh Kumar @ 2006-02-02  8:07 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Marco Costalba, Junio C Hamano, Git Mailing List, Paul Mackerras,
	Marco Costalba
In-Reply-To: <Pine.LNX.4.64.0602012356131.21884@g5.osdl.org>

On 2/2/06, Linus Torvalds <torvalds@osdl.org> wrote:
>
>
> On Thu, 2 Feb 2006, Marco Costalba wrote:
> >
> > Currently the public git repo version of qgit uses "git-diff-tree -c"
> > for merges, It's not a problem to change qgit to use --cc option
> > instead. But I would like to use just one kind of option to filter
> > merges files.
>
> I think using "-c" rather than "--cc" is fine, and if it makes parsing
> easier..
>
> The "--cc" option should show less "noise", an dI'm actually arguing that
> it should show even less than it does now (for when the branches agreed
> with each other, and there was no actual conflict, which is what I think
> is more useful), but I don't think "-c" is _wrong_ either.
>
> Using "-c" is a strange kind of "show all differences in a file that had
> file-level merges" while at least to me "--cc" is meant to be more of a
> "show all actual file-level CONFLICTS where the merge actually did
> something different"


Ok i tried using --cc. But then as per the man page if the
optimization makes the all the hunks disapper then commit log is not
show unless -m is used. Is there a way to get the commit log printed.
BTW using -m didn't show any difference even though man page said
about some difference

-aneesh

^ permalink raw reply

* Re: The merge from hell...
From: Linus Torvalds @ 2006-02-02  8:02 UTC (permalink / raw)
  To: Marco Costalba
  Cc: Junio C Hamano, Git Mailing List, Paul Mackerras, Marco Costalba,
	Aneesh Kumar
In-Reply-To: <e5bfff550602012325s7d0a799ct5bfabbce2c579449@mail.gmail.com>



On Thu, 2 Feb 2006, Marco Costalba wrote:
> 
> Currently the public git repo version of qgit uses "git-diff-tree -c"
> for merges, It's not a problem to change qgit to use --cc option
> instead. But I would like to use just one kind of option to filter
> merges files.

I think using "-c" rather than "--cc" is fine, and if it makes parsing 
easier..

The "--cc" option should show less "noise", an dI'm actually arguing that 
it should show even less than it does now (for when the branches agreed 
with each other, and there was no actual conflict, which is what I think 
is more useful), but I don't think "-c" is _wrong_ either.

Using "-c" is a strange kind of "show all differences in a file that had 
file-level merges" while at least to me "--cc" is meant to be more of a 
"show all actual file-level CONFLICTS where the merge actually did 
something different"

		Linus

^ permalink raw reply

* Re: The merge from hell...
From: Linus Torvalds @ 2006-02-02  7:55 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Git Mailing List, Paul Mackerras, Marco Costalba, Aneesh Kumar,
	Len Brown
In-Reply-To: <Pine.LNX.4.64.0602012334360.21884@g5.osdl.org>



On Wed, 1 Feb 2006, Linus Torvalds wrote:
> 
> Not under my suggested "two version" rule.

That "Not" is just me being stupid. I'm agreeing with you, not 
disagreeing, I just misread your mail.

I _think_ your version of the rule ("pluses and minuses in all the same 
columns") ends up being exactly the same as my rule ("only two different 
versions").

		Linus

^ permalink raw reply

* Re: The merge from hell...
From: Linus Torvalds @ 2006-02-02  7:51 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Git Mailing List, Paul Mackerras, Marco Costalba, Aneesh Kumar,
	Len Brown
In-Reply-To: <7v8xsuuto5.fsf@assigned-by-dhcp.cox.net>



On Wed, 1 Feb 2006, Junio C Hamano wrote:
> 
> > It's commit 9fdb62af92c741addbea15545f214a6e89460865, and passing it to 
> > git-diff-tree with the "--cc" option seems to do the largely the right 
> > thing (although arguably, since one of the parents always matches the end 
> > result in all the files, it shouldn't have shown anything at all, so I 
> > think it could do with some tweaking).
> 
> Hmph.  Do you mean a hunk like this?
> 
> diff --cc kernel/sys.c
> @@@@@@@@@@@@@ +33,7 @@@@@@@@@@@@@
> 
>             #include <linux/compat.h>
>             #include <linux/syscalls.h>
>    + +++    #include <linux/kprobes.h>
> 
>             #include <asm/uaccess.h>
>             #include <asm/io.h>

Yes.

> Currently I cull hunks that have changes from only one parent,
> or when the changes are the same from all but one parent.  This
> hunk does not match either criteria.

Correct. I think "git-diff-tree --cc" actually works as you advertized, 
but that we should change the rules. More akin to

 - if there are only two versions of a hunk, and one of those versions 
   ended up in the result, the hunk is considered successfully merged
   and should be ignored under "--cc"

Under that rule, the kernel/sys.c hunk you specify is indeed 
uninteresting, because there are only two versions: the version that 
didn't have the addition, and the version that did.

> or "plus and minus in the same set of columns" hunks.  If I did
> so, this would become uninteresting:
> 
> diff --cc arch/ia64/pci/pci.c
> @@@@@@@@@@@@@ +709,7 @@@@@@@@@@@@@
>              */
>             int ia64_pci_legacy_write(struct pci_dev *bus, u16...
>             {
>   ------ -  	int ret = 0;
>   ++++++ +  	int ret = size;
>             
>             	switch (size) {
>             	case 1:

Yes. Again, only two versions. Either it was "ret = 0" or it was "ret = 
size". No other version existed in any branch or in the end result, so 
there really were only two versions, and one of them ended up being the 
end result.

> But this is still interesting:
> 
> @@@@@@@@@@@@@ +308,35 @@@@@@@@@@@@@
>             			goto end;
>             		}
>             	}
>   --        	cx->usage++;
>   --        
>             
>      +++    #ifdef CONFIG_HOTPLUG_CPU
>      +++    	/*

Not under my suggested "two version" rule.

The above has _three_ versions: the one with no changes, the one with 
"cx->usage++" removed and the one with "#ifdef CONFIG_HOTPLUG_CPU" added.

So under the two-version rule, the last one would still be interesting.

> > git-diff-tree takes almost three seconds to get its result, though.
> 
> One trivial thing I should be able to do to speed things up is
> to reuse previous diff with other parents.

Yes. In this example, it would apparently cut down the work by a third for 
that file, although it migt make it harder to calculate the proper "-/+" 
patterns..

> I did not expect anybody to be _that_ sick (eh, pardon my
> language) to do a 12-way octpus, so I did not consider this
> optimization possibility, but I should be doing only 4 diffs to
> format -c for this commit.  Currently I do 12.

I agree, I wouldn't have considered that 12-way merge sane either, but 
hey, it worked, and our octopus merge rules are simple enough that I guess 
there's not really any downside to it.

And I was actually happy to have "git-diff-tree --cc" to look at it, and 
that "gitk" eventually gave results that looked decent. I didn't go 
through it all that closely, but the ones I _looked_ at looked fine, and 
it was mighty pleasant to have the tools to look more closely.

So thanks for "--cc" yet again.

> > So think of it as a correctness/scalability test.
> 
> Heh.  I like this one as a practice.  Thanks!

Thank Len. He may have done it as a way to avoid having extra merges, 
since I complained about those last time ;)

		Linus

^ permalink raw reply

* [PATCH] combine-diff: reuse diff from the same blob.
From: Junio C Hamano @ 2006-02-02  7:40 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Linus Torvalds, Paul Mackerras, Marco Costalba, Aneesh Kumar
In-Reply-To: <7v8xsuuto5.fsf@assigned-by-dhcp.cox.net>

When dealing with an insanely large Octopus, it is possible to
optimize by noticing that more than one parents have the same
blob and avoid running diff between a parent and the merge
result by reusing an earlier result.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 Junio C Hamano <junkio@cox.net> writes:

 > One trivial thing I should be able to do to speed things up is
 > to reuse previous diff with other parents.  For example, that
 > commit does this to kernel/sys.c from its 12 parents.
 >
 > :100644 100644 d09cac2... 0929c69... M  kernel/sys.c
 > :100644 100644 eecf845... 0929c69... M  kernel/sys.c
 > :100644 100644 c3b1874... 0929c69... M  kernel/sys.c
 > :100644 100644 bce933e... 0929c69... M  kernel/sys.c
 > :100644 100644 eecf845... 0929c69... M  kernel/sys.c
 > :100644 100644 bce933e... 0929c69... M  kernel/sys.c
 > :100644 100644 bce933e... 0929c69... M  kernel/sys.c
 > :100644 100644 bce933e... 0929c69... M  kernel/sys.c
 > :100644 100644 eecf845... 0929c69... M  kernel/sys.c
 > :100644 100644 eecf845... 0929c69... M  kernel/sys.c
 > :100644 100644 eecf845... 0929c69... M  kernel/sys.c
 > :100644 100644 eecf845... 0929c69... M  kernel/sys.c
 >
 > Running "sort -u" on these would leave only 4 lines.
 >
 > I did not expect anybody to be _that_ sick (eh, pardon my
 > language) to do a 12-way octpus, so I did not consider this
 > optimization possibility, but I should be doing only 4 diffs to
 > format -c for this commit.  Currently I do 12.

 On my Duron 750 w/ 770MB RAM here is the results.

 Without this optimization:
 real	0m11.117s	user	0m9.230s	sys	0m1.860s
 With this optimization:
 real	0m7.339s	user	0m6.730s	sys	0m0.610s

 combine-diff.c |   39 +++++++++++++++++++++++++++++++++++++--
 1 files changed, 37 insertions(+), 2 deletions(-)

7bf761b73cfb74917454e179d95f0dab1cab8f0b
diff --git a/combine-diff.c b/combine-diff.c
index 243f967..0cc18fe 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -523,6 +523,30 @@ static void dump_sline(struct sline *sli
 	}
 }
 
+static void reuse_combine_diff(struct sline *sline, unsigned long cnt,
+			       int i, int j)
+{
+	/* We have already examined parent j and we know parent i
+	 * and parent j are the same, so reuse the combined result
+	 * of parent j for parent i.
+	 */
+	unsigned long lno, imask, jmask;
+	imask = (1UL<<i);
+	jmask = (1UL<<j);
+
+	for (lno = 0; lno < cnt; lno++) {
+		struct lline *ll = sline->lost_head;
+		while (ll) {
+			if (ll->parent_map & jmask)
+				ll->parent_map |= imask;
+			ll = ll->next;
+		}
+		if (!(sline->flag & jmask))
+			sline->flag &= ~imask;
+		sline++;
+	}
+}
+
 int show_combined_diff(struct combine_diff_path *elem, int num_parent,
 		       int dense, const char *header, int show_empty)
 {
@@ -596,8 +620,19 @@ int show_combined_diff(struct combine_di
 		sline[cnt-1].flag = (1UL<<num_parent) - 1;
 	}
 
-	for (i = 0; i < num_parent; i++)
-		combine_diff(elem->parent_sha1[i], ourtmp, sline, cnt, i);
+	for (i = 0; i < num_parent; i++) {
+		int j;
+		for (j = 0; j < i; j++) {
+			if (!memcmp(elem->parent_sha1[i],
+				    elem->parent_sha1[j], 20)) {
+				reuse_combine_diff(sline, cnt, i, j);
+				break;
+			}
+		}
+		if (i <= j)
+			combine_diff(elem->parent_sha1[i], ourtmp, sline,
+				     cnt, i);
+	}
 
 	show_hunks = make_hunks(sline, cnt, num_parent, dense);
 
-- 
1.1.6.g2672

^ permalink raw reply related

* Re: The merge from hell...
From: Marco Costalba @ 2006-02-02  7:25 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Junio C Hamano, Git Mailing List, Paul Mackerras, Marco Costalba,
	Aneesh Kumar
In-Reply-To: <Pine.LNX.4.64.0602012212200.21884@g5.osdl.org>

On 2/2/06, Linus Torvalds <torvalds@osdl.org> wrote:
>

> Btw, I think you're better off parsing the "git-diff-tree --cc" output
> than doing it yourself like gitk does, now that core git has support for
> things like that.
>

Currently the public git repo version of qgit uses "git-diff-tree -c"
for merges, It's not a problem to change qgit to use --cc option
instead. But I would like to use just one kind of option to filter
merges files.

So I would like to hear some feedback on using --cc vs -c.

Marco

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox