git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[RFC] More diff possibilities in gitweb

From
MKMartin Koegler <mkoegler@auto.tuwien.ac.at>
Date
Mar 17, 2007, 15:17 UTC
Message-ID
<20070317151731.GA32571@auto.tuwien.ac.at>

Compared to eg. viewcvs, gitweb offers fewer possibilies to do a diff. With viewcvs, you can compare arbitrary version of a file; gitweb only offers diff to previous (or sometimes current) version.

As git offers an infinite number of possible (and maybe useful) diffs,
I added to each each compareable object two links:
* "base": Select this object as parent
* "diff": Diff against the last select parent

The selected parent object is stored as a cookie, so it is possible to do a diff between objects shown on different pages.

The whole is implemented in JavaScript on the client side (tested with IE 6 and Mozilla). On the server side, only the JavaScript file is included in the output (see below). The link generation is done completely in the browser.

The patch offers the following possibilies:
* Compare any commit with an other commit
  Passes the hashes of the two commits as h and hp to commitdiff
  function. The output includes the message of one commit, which can
  be confusing.
* Compare any blob with an other blob
  This feature is based on the blobdiff function. There are two types
  of blob:
  - blobs in the tree view can be compared with any blob in the tree view.
  - blobs in the history view can only be compared with any blob with
    the same file name in the history view.
* Compare trees
  gitweb currently has no function for comparing trees. I currently
  misused blobdiff for this. The content of the diff is OK, only the
  filenames are wrong/destroyed. Additionally gitweb issus some "Use
  of uninitialized value" message to the error log.
  A proper implementation would need new function in gitweb.cgi,
  basically git_commitdiff removing the requirement, that the hashes
  must be a commit.
Is there an interest these function?
mfg Martin Kögler
Patch for gitweb.cgi (in function git_footer_html):
---------------------------------------------------
 
+        print '<script type="text/javascript" src="gitweb.js"></script>';
         print "</body>\n" .
               "</html>";
File gitweb.js:
---------------
function getCookie(name)
{
  var name=name+"=";
  var c=document.cookie;
  var p=c.indexOf(name);
  if(p==-1)
    return null;
  c=c.substr(p+name.length,c.length);
  p=c.indexOf(";");
  if(p==-1)
    return c;
  else
    return c.substr(0, p);
}
function insertAfter(elem, node)
{
  if(node.nextSibling)
    node.parentNode.insertBefore(elem, node.nextSibling);
  else
    node.parentNode.appendChild(elem);
}
function createLink(href, linktext)
{
  var l=document.createElement("a");
  l.appendChild(document.createTextNode(linktext));
  l.href=href;
  return l;
}
function createLinkGroup(href1, basetxt, href2, difftxt)
{
  var l=document.createElement("span");
  l.appendChild(document.createTextNode(" ("));
  l.appendChild(createLink(href1, basetxt));
  l.appendChild(document.createTextNode(" | "));
  l.appendChild(createLink(href2, difftxt));
  l.appendChild(document.createTextNode(") "));
  return l;
}
function GitRef()
{
    this.t=null;
    this.h=null;
    this.hb=null;
    this.f=null;
    this.ToRef=ToRef;
}
function ToRef()
{
  var parts=new Array();
  if(this.f)
    parts.push("f="+this.f);
  if(this.h)
    parts.push("h="+this.h);
  if(this.hb)
    parts.push("hb="+this.hb);
  if(this.t)
    parts.push("t="+this.t);
  return parts.join("@");
}
function splitGitRef(ref)
{
  var parts=ref.split("@");
  var res=new GitRef();
  var i;
  for(i=0;i<parts.length;i++)
  {
      var p=parts[i].split("=");
      res[p[0]]=p[1];
  }
  return res;
}
function GitURL(base)
{
  this.base=base;
  this.p=null;
  this.a=null;
  this.f=null;
  this.fp=null;
  this.h=null;
  this.hp=null;
  this.hb=null;
  this.hpb=null;
  this.pg=null;
  this.o=null;
  this.s=null;
  this.st=null;
  this.ToURL=ToURL;
  this.ToRef=UrlToRef;
  this.ToDUrl=ToDUrl;
}
function ToURL()
{
  var parts=new Array();
  if(this.p)
    parts.push("p="+this.p);
  if(this.a)
    parts.push("a="+this.a);
  if(this.f)
    parts.push("f="+this.f);
  if(this.fp)
    parts.push("fp="+this.fp);
  if(this.h)
    parts.push("h="+this.h);
  if(this.hp)
    parts.push("hp="+this.hp);
  if(this.hb)
    parts.push("hb="+this.hb);
  if(this.hpb)
    parts.push("hpb="+this.hpb);
  if(this.o)
    parts.push("o="+this.o);
  if(this.s)
    parts.push("s="+this.s);
  if(this.st)
    parts.push("st="+this.st);
  return this.base+"?"+parts.join(";");
}
function UrlToRef(type)
{
    var res=new GitRef;
    res.f=this.f;
    res.h=this.h;
    res.hb=this.hb;
    res.t=type;
    return res.ToRef();
}
function ToDUrl(type)
{
    var res=new GitURL(this.base);
    res.f=this.f;
    res.h=this.h;
    res.hb=this.hb;
    res.p=this.p;
    res.a=type;
    return res.ToURL();
}
function splitGitURL(url)
{
  var Urls=url.split("?");
  var res=new GitURL(Urls[0]);
  if(Urls.length>1)
    {
      var parts=Urls[1].split(";");
      var i;
      for(i=0;i<parts.length;i++)
	{
	  var p=parts[i].split("=");
	  res[p[0]]=p[1];
	}
    }
  return res;
}
function GitAddLinks()
{
  var links=document.getElementsByTagName("a");
  var i;
  for(i=0;i<links.length;i++)
    {
      var link=links[i];
      if(link.innerHTML=='commit')
	{
	  var url=splitGitURL(link.href);
	  if(!url.h)
	    continue;
	  var l=createLinkGroup("javascript:base('"+url.ToRef('commit')+"')","base",
				"javascript:diff('"+url.ToDUrl('commit')+"')","diff");
	  insertAfter(l, link);
	}
      if(link.innerHTML=='blob')
	{
	  var url=splitGitURL(link.href);
	  if(!url.h&&!(url.hb&&url.f))
	    continue;
	  var l=createLinkGroup("javascript:base('"+url.ToRef('blob')+"')","base",
				"javascript:diff('"+url.ToDUrl('blob')+"')","diff");
	  insertAfter(l, link);
	}
      if(link.innerHTML=='tree')
	{
	  var url=splitGitURL(link.href);
	  if(!url.h)
	    continue;
	  var l=createLinkGroup("javascript:base('"+url.ToRef('tree')+"')","base",
				"javascript:diff('"+url.ToDUrl('tree')+"')","diff");
	  insertAfter(l, link);
	}
    }
}
function base(ref)
{
  document.cookie="basename="+ref;
}
function diff(url)
{
  var c=getCookie("basename");
  if (!c)
  {
      alert("no diff base selected");
      return;
  }
  c=splitGitRef(c);
  url=splitGitURL(url);
  if(c.t=='commit'&&url.a=='commit')
  {
      url.a='commitdiff';
      if(!c.h||!url.h)
      {
	  alert("commit diff not possible");
	  return;
      }
      url.hb=null;
      url.f=null;
      url.hp=c.h;
      document.location.href=url.ToURL();
      return;
  }
  if(c.t=='blob'&&url.a=='blob')
  {
      url.a='blobdiff';
      if(c.h&&url.h)
      {
	  url.hb=null;
	  url.hp=c.h;
	  url.fp=c.f;
      } 
      else if (c.hb&&url.hb&&url.f&&c.f)
      {
	  if (url.f!=c.f)
	  {
	      alert("file name do not match");
	      return;
	  }
	  url.h=null;
	  url.hpb=c.hb;
	  url.fp=c.f;
      }
      else
      {
	  alert("blob diff not possible");
	  return;
      }
      document.location.href=url.ToURL();
      return;
  }
  if(c.t=='tree'&&url.a=='tree')
  {
      url.a='blobdiff';
      if(c.h&&url.h)
      {
	  url.hb=null;
	  url.hp=c.h;
	  url.fp=c.f;
	  document.location.href=url.ToURL();
	  return;
      } 
  }
  alert("diff not possible");
}
GitAddLinks();
Next: Johannes Schindelin
Message 1 of 9 in “[RFC] More diff possibilities in gitweb”
  1. Martin KoeglerMar 17, 2007
  2. Johannes SchindelinMar 17, 2007
  3. Martin KoeglerMar 18, 2007
  4. Jakub NarebskiMar 18, 2007
  5. Martin KoeglerMar 19, 2007
  6. Jakub NarebskiMar 20, 2007
  7. Jakub NarebskiMar 17, 2007
  8. Martin KoeglerMar 18, 2007
  9. Jakub NarebskiMar 18, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.