* Git and tagging hook
From: Kristis Makris @ 2008-10-06 4:45 UTC (permalink / raw)
To: git-u79uwXL29TY76Z2rM5mHXA; +Cc: scmbug-users-G8y9j4K4DsPiwOUmbS1EgQ
[-- Attachment #1.1: Type: text/plain, Size: 366 bytes --]
Hello,
It seems that Git (at least v1.5.6) does not offer hooks on tag creation
(a pre-tag and a post-tag hook). I need such a hook for integrating tag
activities with an issue-tracker. Is it possible to add this hook ?
I had asked about this in the past, but did not receive a response.
http://bugzilla.mkgnu.net/show_bug.cgi?id=991
Thanks,
Kristis
[-- Attachment #1.2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
[-- Attachment #2: Type: text/plain, Size: 188 bytes --]
_______________________________________________
scmbug-users mailing list
scmbug-users-G8y9j4K4DsPiwOUmbS1EgQ@public.gmane.org
http://lists.mkgnu.net/cgi-bin/mailman/listinfo/scmbug-users
^ permalink raw reply
* [PATCH v3] rebase--interactive: fix parent rewriting for dropped commits
From: Stephen Haberman @ 2008-10-06 4:26 UTC (permalink / raw)
To: git; +Cc: ae, spearce
In-Reply-To: <20081003133246.bae6b657.stephen@exigencecorp.com>
`rebase -i -p` got its rev-list of commits to keep by --left-right and
--cherry-pick. Adding --cherry-pick would drop commits that duplicated changes
already in the rebase target.
The dropped commits were then forgotten about when it came to rewriting the
parents of their descendents, so the descendents would get cherry-picked with
their old, unwritten parents and essentially make the rebase a no-op.
This commit adds a $DOTEST/dropped directory to remember dropped commits and
rewrite their children's parent as the dropped commit's possibly-rewritten
first-parent.
Signed-off-by: Stephen Haberman <stephen@exigencecorp.com>
---
These two lines changed from the v2 patch:
pend=" $(cat "$DROPPED"/$p)$pend"
It now puts $p at the start of $pend instead of the end. I have no tests
that assert this behavior (vs. the old of putting it at the end), but it
seems rational to put the dropped-replacement parent first so that the
current commit's parents come out in the same order (otherwise a commit
with parents "p1 p2dropped p3" would end up "p1 p3 p2firstparent").
Also, this line changed:
new_parents="$new_parents $p"
Previously it said "$new_parents $new_p" which was a copy/paste bug--$new_p
was from up in the code a bit and here we just want to use $p.
I also cleaned up the commit message.
git-rebase--interactive.sh | 37 +++++++-
t/t3410-rebase-preserve-dropped-merges.sh | 140 +++++++++++++++++++++++++++++
2 files changed, 175 insertions(+), 2 deletions(-)
create mode 100644 t/t3410-rebase-preserve-dropped-merges.sh
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index edb6ec6..4d53347 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -37,6 +37,7 @@ DONE="$DOTEST"/done
MSG="$DOTEST"/message
SQUASH_MSG="$DOTEST"/message-squash
REWRITTEN="$DOTEST"/rewritten
+DROPPED="$DOTEST"/dropped
PRESERVE_MERGES=
STRATEGY=
ONTO=
@@ -169,8 +170,12 @@ pick_one_preserving_merges () {
# rewrite parents; if none were rewritten, we can fast-forward.
new_parents=
- for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-)
+ pend=" $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-)"
+ while [ "$pend" != "" ]
do
+ p=$(expr "$pend" : ' \([^ ]*\)')
+ pend="${pend# $p}"
+
if test -f "$REWRITTEN"/$p
then
new_p=$(cat "$REWRITTEN"/$p)
@@ -183,7 +188,13 @@ pick_one_preserving_merges () {
;;
esac
else
- new_parents="$new_parents $p"
+ if test -f "$DROPPED"/$p
+ then
+ fast_forward=f
+ pend=" $(cat "$DROPPED"/$p)$pend"
+ else
+ new_parents="$new_parents $p"
+ fi
fi
done
case $fast_forward in
@@ -582,6 +593,28 @@ first and then run 'git rebase --continue' again."
#
EOF
+ # Watch for commits that been dropped by --cherry-pick
+ if test t = "$PRESERVE_MERGES"
+ then
+ mkdir "$DROPPED"
+ # drop the --cherry-pick parameter this time
+ git rev-list $MERGES_OPTION --abbrev-commit \
+ --abbrev=7 $UPSTREAM...$HEAD --left-right | \
+ sed -n "s/^>//p" | while read rev
+ do
+ grep --quiet "$rev" "$TODO"
+ if [ $? -ne 0 ]
+ then
+ # Use -f2 because if rev-list is telling this commit is not
+ # worthwhile, we don't want to track its multiple heads,
+ # just the history of its first-parent for others that will
+ # be rebasing on top of us
+ full=$(git rev-parse $rev)
+ git rev-list --parents -1 $rev | cut -d' ' -f2 > "$DROPPED"/$full
+ fi
+ done
+ fi
+
has_action "$TODO" ||
die_abort "Nothing to do"
diff --git a/t/t3410-rebase-preserve-dropped-merges.sh b/t/t3410-rebase-preserve-dropped-merges.sh
new file mode 100644
index 0000000..7c8862b
--- /dev/null
+++ b/t/t3410-rebase-preserve-dropped-merges.sh
@@ -0,0 +1,140 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 Stephen Haberman
+#
+
+test_description='git rebase preserve merges
+
+This test runs git rebase with preserve merges and ensures commits
+dropped by the --cherry-pick flag have their childrens parents
+rewritten.
+'
+. ./test-lib.sh
+
+# set up two branches like this:
+#
+# A - B - C - D - E
+# \
+# F - G - H
+# \
+# I
+#
+# where B, D and G touch the same file.
+
+test_expect_success 'setup' '
+ : > file1 &&
+ git add file1 &&
+ test_tick &&
+ git commit -m A &&
+ git tag A &&
+ echo 1 > file1 &&
+ test_tick &&
+ git commit -m B file1 &&
+ : > file2 &&
+ git add file2 &&
+ test_tick &&
+ git commit -m C &&
+ echo 2 > file1 &&
+ test_tick &&
+ git commit -m D file1 &&
+ : > file3 &&
+ git add file3 &&
+ test_tick &&
+ git commit -m E &&
+ git tag E &&
+ git checkout -b branch1 A &&
+ : > file4 &&
+ git add file4 &&
+ test_tick &&
+ git commit -m F &&
+ git tag F &&
+ echo 3 > file1 &&
+ test_tick &&
+ git commit -m G file1 &&
+ git tag G &&
+ : > file5 &&
+ git add file5 &&
+ test_tick &&
+ git commit -m H &&
+ git tag H &&
+ git checkout -b branch2 F &&
+ : > file6 &&
+ git add file6 &&
+ test_tick &&
+ git commit -m I &&
+ git tag I
+'
+
+# A - B - C - D - E
+# \ \ \
+# F - G - H -- L \ --> L
+# \ | \
+# I -- G2 -- J -- K I -- K
+# G2 = same changes as G
+test_expect_success 'skip same-resolution merges with -p' '
+ git checkout branch1 &&
+ ! git merge E &&
+ echo 23 > file1 &&
+ git add file1 &&
+ git commit -m L &&
+ git checkout branch2 &&
+ echo 3 > file1 &&
+ git commit -a -m G2 &&
+ ! git merge E &&
+ echo 23 > file1 &&
+ git add file1 &&
+ git commit -m J &&
+ echo file7 > file7 &&
+ git add file7 &&
+ git commit -m K &&
+ GIT_EDITOR=: git rebase -i -p branch1 &&
+ test $(git rev-parse branch2^^) = $(git rev-parse branch1) &&
+ test "23" = "$(cat file1)" &&
+ test "" = "$(cat file6)" &&
+ test "file7" = "$(cat file7)" &&
+
+ git checkout branch1 &&
+ git reset --hard H &&
+ git checkout branch2 &&
+ git reset --hard I
+'
+
+# A - B - C - D - E
+# \ \ \
+# F - G - H -- L \ --> L
+# \ | \
+# I -- G2 -- J -- K I -- G2 -- K
+# G2 = different changes as G
+test_expect_success 'keep different-resolution merges with -p' '
+ git checkout branch1 &&
+ ! git merge E &&
+ echo 23 > file1 &&
+ git add file1 &&
+ git commit -m L &&
+ git checkout branch2 &&
+ echo 4 > file1 &&
+ git commit -a -m G2 &&
+ ! git merge E &&
+ echo 24 > file1 &&
+ git add file1 &&
+ git commit -m J &&
+ echo file7 > file7 &&
+ git add file7 &&
+ git commit -m K &&
+ ! GIT_EDITOR=: git rebase -i -p branch1 &&
+ echo 234 > file1 &&
+ git add file1 &&
+ GIT_EDITOR=: git rebase --continue &&
+ test $(git rev-parse branch2^^^) = $(git rev-parse branch1) &&
+ test "234" = "$(cat file1)" &&
+ test "" = "$(cat file6)" &&
+ test "file7" = "$(cat file7)" &&
+
+ git checkout branch1 &&
+ git reset --hard H &&
+ git checkout branch2 &&
+ git reset --hard I
+'
+
+test_done
+
--
1.6.0.2
^ permalink raw reply related
* Re: git svn: Bad URL passed to RA layer: Unrecognized URL scheme
From: Jeff Kowalczyk @ 2008-10-06 2:28 UTC (permalink / raw)
To: git
In-Reply-To: <237967ef0810051244m51156925x26ae51db038dad49@mail.gmail.com>
Mikael Magnusson wrote:
> That somehow looks more like an svn error than a git error, does
> svn checkout http://code.djangoproject.com/svn work?
You were correct, I tried subversion and got the same error. I rebuilt
(gentoo ~x86) neon-0.28.3, subversion-1.5.2 and git-1.6.0.2, and have
functional git svn operations.
However, each operation ends with a segmentation fault. This is the case
with all git svn repositories (e.g. several different svn remote hosts).
(master) $ git svn rebase
M django/core/management/commands/makemessages.py
M docs/topics/i18n.txt
r9155 = 4c86e60f62366ac9c3fd9369c17c54801a8f2ea0 (trunk)
First, rewinding head to replay your work on top of it...
Fast-forwarded master to refs/remotes/trunk.
Segmentation fault
Does the segfault risk corruption of the git repository data?
Would I report this as a git bug or distribution bug?
Thanks.
^ permalink raw reply
* Re: git UI feature matrix (was: Re: teamGit v0.0.3)
From: Martin Langhoff @ 2008-10-06 1:52 UTC (permalink / raw)
To: Stephan Beyer; +Cc: bain, git
In-Reply-To: <20081006013303.GB25639@leksak.fem-net>
On Mon, Oct 6, 2008 at 2:33 PM, Stephan Beyer <s-beyer@gmx.net> wrote:
> Hi,
>
> bain wrote:
>> > Could you please add info about teamGit to the git wiki page
>> > http://git.or.cz/gitwiki/InterfacesFrontendsAndTools? I think
>> > just below now defunct and unmaintained KGit (or just above) would
>> > be best.
>> Will do ASAP
>
> Because there are a lot of UIs and GUIs for git I thought a "feature
> matrix" could be cool. I created a stub on the mentioned wiki page.
I volunteer to start a "give a beer to a programmer that eschews
writing his own and helps others polish/extend an existing one" fund
:-p
cheers,
m
--
martin.langhoff@gmail.com
martin@laptop.org -- School Server Architect
- ask interesting questions
- don't get distracted with shiny stuff - working code first
- http://wiki.laptop.org/go/User:Martinlanghoff
^ permalink raw reply
* git UI feature matrix (was: Re: teamGit v0.0.3)
From: Stephan Beyer @ 2008-10-06 1:33 UTC (permalink / raw)
To: bain; +Cc: git
In-Reply-To: <22717858-31ce-4979-9d8e-167601f0e82e@i24g2000prf.googlegroups.com>
Hi,
bain wrote:
> > Could you please add info about teamGit to the git wiki page
> > http://git.or.cz/gitwiki/InterfacesFrontendsAndTools? I think
> > just below now defunct and unmaintained KGit (or just above) would
> > be best.
> Will do ASAP
Because there are a lot of UIs and GUIs for git I thought a "feature
matrix" could be cool. I created a stub on the mentioned wiki page.
So it'd be nice if you could add a column for teamGit there and perhaps
some rows for features that are worth mentioning (if those already exist
in teamGit).
I was unsure what features are useful to mention, because I do not really
use git GUIs. (I only use gitk for history viewing, but only when I'm
too lazy to type "git log --decorate --graph".)
Regards,
Stephan
PS: Such a feature matrix could also be useful for the git web
interfaces.
--
Stephan Beyer <s-beyer@gmx.net>, PGP 0x6EDDD207FCC5040F
^ permalink raw reply
* Re: [PATCHv4] gitweb: generate parent..current URLs
From: Jakub Narebski @ 2008-10-06 0:17 UTC (permalink / raw)
To: Giuseppe Bilotta; +Cc: git, Petr Baudis, Junio C Hamano, Shawn O. Pearce
In-Reply-To: <1222906234-8182-7-git-send-email-giuseppe.bilotta@gmail.com>
On Thu, 2 Oct 2008, Giuseppe Bilotta wrote:
> If use_pathinfo is enabled, href now creates links that contain paths in
> the form $project/$action/oldhash:/oldname..newhash:/newname for actions
> that use hash_parent etc.
[cut]
>From the first glance, it looks good. I just worry a bit about
complicated issue of hash_parent vs hash_parent_base etc.
--
Jakub Narebski
Poland
^ permalink raw reply
* Re: gitweb improvements
From: Jakub Narebski @ 2008-10-05 23:54 UTC (permalink / raw)
To: Tjernlund; +Cc: 'git'
In-Reply-To: <00b201c92739$36585eb0$a3091c10$@se>
On Mon, 6 Oct 2008, Tjernlund wrote:
> Jakub Narebski wrote:
>> "Tjernlund" <tjernlund@tjernlund.se> writes:
>>> 2) looking at a merge like:
>>> http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=66120005e65eed8a05b14a36ab448bdec42f0d6b
>>> is somewhat confusing. It really doesn't tell you which commits that is
>>> included in the merge.
>>
>> I don't understand you there. First, you have "(merge: 0d0f3ef 9778e9a)"
>> in the navbar, so you can easily go to commit view for parents. Second,
>> among commit headers you have two "parent", where SHA-1 of a commit is
>> hidden link, and there are also 'commit' and 'diff' link for those.
>
> hmm, looks like I overlooked "(merge: 0d0f3ef 9778e9a)" part. However, I can't
> find the "ALSA: make the CS4270 driver a new-style I2C driver" from within
> this page.
I think you don't quite understand the situation. The history looks
like this:
M Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
|\
| 2 ALSA: ASoC: Fix another cs4270 error path
| * ALSA: make the CS4270 driver a new-style I2C driver
| |
1 | Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6
Parents of commit 'M' (for merge) are '1' and '2', not 2,* or 1,2,*.
Now the fact that commit message for merge contains shortlog of merged
branch does not mean that there must be direct link to such shortlog.
You can go to shortlog (well, kind of) if you click on second parent,
_then_ click on shortlog link at top of the page.
--
Jakub Narebski
Poland
^ permalink raw reply
* [EGIT PATCH 4/6] Add tags to the graphical history display.
From: Robin Rosenberg @ 2008-10-05 23:36 UTC (permalink / raw)
To: git; +Cc: spearce, Robin Rosenberg
In-Reply-To: <1223249802-9959-4-git-send-email-robin.rosenberg@dewire.com>
Both the SWT (Eclipse) drawing and Swing versions are updated.
The coloring and shapes are intentionally not the same as for gitk.
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
.../egit/core/internal/storage/KidWalk.java | 3 +-
.../egit/ui/internal/history/SWTCommit.java | 5 +-
.../egit/ui/internal/history/SWTPlotRenderer.java | 64 +++++++++++++++++++-
.../spearce/egit/ui/internal/history/SWTWalk.java | 5 +-
.../org/spearce/jgit/awtui/AWTPlotRenderer.java | 46 ++++++++++++++
.../spearce/jgit/revplot/AbstractPlotRenderer.java | 18 +++++-
.../src/org/spearce/jgit/revplot/PlotCommit.java | 8 ++-
.../src/org/spearce/jgit/revplot/PlotWalk.java | 56 ++++++++++++++++-
.../src/org/spearce/jgit/revwalk/RevWalk.java | 19 +++++-
9 files changed, 209 insertions(+), 15 deletions(-)
diff --git a/org.spearce.egit.core/src/org/spearce/egit/core/internal/storage/KidWalk.java b/org.spearce.egit.core/src/org/spearce/egit/core/internal/storage/KidWalk.java
index 6b8f468..b337efe 100644
--- a/org.spearce.egit.core/src/org/spearce/egit/core/internal/storage/KidWalk.java
+++ b/org.spearce.egit.core/src/org/spearce/egit/core/internal/storage/KidWalk.java
@@ -11,6 +11,7 @@
import org.spearce.jgit.lib.AnyObjectId;
import org.spearce.jgit.lib.Repository;
import org.spearce.jgit.revwalk.RevCommit;
+import org.spearce.jgit.lib.Ref;
import org.spearce.jgit.revwalk.RevWalk;
class KidWalk extends RevWalk {
@@ -19,7 +20,7 @@ KidWalk(final Repository repo) {
}
@Override
- protected RevCommit createCommit(final AnyObjectId id) {
+ protected RevCommit createCommit(final AnyObjectId id, final Ref[] tags) {
return new KidCommit(id);
}
}
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/SWTCommit.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/SWTCommit.java
index fa0d25d..2341fbd 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/SWTCommit.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/SWTCommit.java
@@ -10,12 +10,13 @@
import org.eclipse.swt.widgets.Widget;
import org.spearce.jgit.lib.AnyObjectId;
import org.spearce.jgit.revplot.PlotCommit;
+import org.spearce.jgit.lib.Ref;
class SWTCommit extends PlotCommit<SWTCommitList.SWTLane> {
Widget widget;
- SWTCommit(final AnyObjectId id) {
- super(id);
+ SWTCommit(final AnyObjectId id, final Ref[] tags) {
+ super(id, tags);
}
@Override
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/SWTPlotRenderer.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/SWTPlotRenderer.java
index 23ec255..56d5842 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/SWTPlotRenderer.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/SWTPlotRenderer.java
@@ -15,7 +15,10 @@
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.ui.themes.ColorUtil;
import org.spearce.egit.ui.internal.history.SWTCommitList.SWTLane;
+import org.spearce.jgit.lib.Constants;
+import org.spearce.jgit.lib.Ref;
import org.spearce.jgit.revplot.AbstractPlotRenderer;
import org.spearce.jgit.revplot.PlotCommit;
@@ -26,7 +29,13 @@
private final Color sys_gray;
- private Color sys_darkblue;
+ private final Color sys_darkblue;
+
+ private final Color sys_yellow;
+
+ private final Color sys_green;
+
+ private final Color sys_white;
GC g;
@@ -43,6 +52,9 @@ SWTPlotRenderer(final Display d) {
sys_black = d.getSystemColor(SWT.COLOR_BLACK);
sys_gray = d.getSystemColor(SWT.COLOR_GRAY);
sys_darkblue = d.getSystemColor(SWT.COLOR_DARK_BLUE);
+ sys_yellow = d.getSystemColor(SWT.COLOR_YELLOW);
+ sys_green = d.getSystemColor(SWT.COLOR_GREEN);
+ sys_white = d.getSystemColor(SWT.COLOR_WHITE);
}
void paint(final Event event) {
@@ -92,7 +104,57 @@ protected void drawText(final String msg, final int x, final int y) {
g.drawString(msg, cellX + x, cellY + texty);
}
+ @Override
+ protected int drawLabel(int x, int y, Ref ref) {
+ String txt;
+ String name = ref.getOrigName();
+ if (name.startsWith(Constants.R_HEADS)) {
+ g.setBackground(sys_green);
+ txt = name.substring(Constants.R_HEADS.length());
+ } else if (name.startsWith(Constants.R_REMOTES)){
+ g.setBackground(sys_gray);
+ txt = name.substring(Constants.R_REMOTES.length());
+ } else if (name.startsWith(Constants.R_TAGS)){
+ g.setBackground(sys_yellow);
+ txt = name.substring(Constants.R_TAGS.length());
+ } else {
+ // Whatever this would be
+ g.setBackground(sys_white);
+ if (name.startsWith(Constants.R_REFS))
+ txt = name.substring(Constants.R_REFS.length());
+ else
+ txt = name; // HEAD and such
+ }
+ Color peeledColor = null;
+ if (ref.getPeeledObjectId() != null) {
+ peeledColor = new Color(g.getDevice(), ColorUtil.blend(g.getBackground().getRGB(), sys_white.getRGB()));
+ g.setBackground(peeledColor);
+ }
+ if (txt.length() > 12)
+ txt = txt.substring(0,11) + "\u2026"; // ellipsis "â¦" (in UTF-8)
+
+ Point testsz = g.stringExtent(txt);
+ final int texty = (y * 2 - testsz.y) / 2;
+ g.setForeground(sys_black);
+ g.drawString(txt, x + 2, cellY + texty);
+ g.setLineWidth(2);
+ Color blend1 = new Color(g.getDevice(), ColorUtil.blend(g.getBackground().getRGB(), sys_gray.getRGB()));
+ g.setForeground(blend1);
+ g.drawRoundRectangle(x, cellY + texty -2, testsz.x + 3, testsz.y + 3, testsz.y/4, testsz.y/4);
+ g.setLineWidth(2);
+ Color blend2 = new Color(g.getDevice(), ColorUtil.blend(g.getBackground().getRGB(), sys_black.getRGB()));
+ g.setForeground(blend2);
+ g.drawRoundRectangle(x + 1, cellY + texty -1, testsz.x + 1, testsz.y + 1, testsz.y/4, testsz.y/4);
+
+ blend1.dispose();
+ blend2.dispose();
+ if (peeledColor != null)
+ peeledColor.dispose();
+ return 8 + testsz.x;
+ }
+
protected Color laneColor(final SWTLane myLane) {
return myLane != null ? myLane.color : sys_black;
}
+
}
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/SWTWalk.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/SWTWalk.java
index 527d284..bc347db 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/SWTWalk.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/SWTWalk.java
@@ -11,6 +11,7 @@
import org.spearce.jgit.lib.Repository;
import org.spearce.jgit.revplot.PlotWalk;
import org.spearce.jgit.revwalk.RevCommit;
+import org.spearce.jgit.lib.Ref;
class SWTWalk extends PlotWalk {
SWTWalk(final Repository repo) {
@@ -18,7 +19,7 @@ SWTWalk(final Repository repo) {
}
@Override
- protected RevCommit createCommit(final AnyObjectId id) {
- return new SWTCommit(id);
+ protected RevCommit createCommit(final AnyObjectId id, final Ref[] tags) {
+ return new SWTCommit(id, tags);
}
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/awtui/AWTPlotRenderer.java b/org.spearce.jgit/src/org/spearce/jgit/awtui/AWTPlotRenderer.java
index b6b715c..5dcddf5 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/awtui/AWTPlotRenderer.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/awtui/AWTPlotRenderer.java
@@ -44,6 +44,8 @@
import org.spearce.jgit.awtui.CommitGraphPane.GraphCellRender;
import org.spearce.jgit.awtui.SwingCommitList.SwingLane;
+import org.spearce.jgit.lib.Constants;
+import org.spearce.jgit.lib.Ref;
import org.spearce.jgit.revplot.AbstractPlotRenderer;
import org.spearce.jgit.revplot.PlotCommit;
@@ -134,4 +136,48 @@ void paintTriangleDown(final int cx, final int y, final int h) {
g.drawPolygon(triangle);
}
+ @Override
+ protected int drawLabel(int x, int y, Ref ref) {
+ String txt;
+ String name = ref.getOrigName();
+ if (name.startsWith(Constants.R_HEADS)) {
+ g.setBackground(Color.GREEN);
+ txt = name.substring(Constants.R_HEADS.length());
+ } else if (name.startsWith(Constants.R_REMOTES)){
+ g.setBackground(Color.LIGHT_GRAY);
+ txt = name.substring(Constants.R_REMOTES.length());
+ } else if (name.startsWith(Constants.R_TAGS)){
+ g.setBackground(Color.YELLOW);
+ txt = name.substring(Constants.R_TAGS.length());
+ } else {
+ // Whatever this would be
+ g.setBackground(Color.WHITE);
+ if (name.startsWith(Constants.R_REFS))
+ txt = name.substring(Constants.R_REFS.length());
+ else
+ txt = name; // HEAD and such
+ }
+ if (ref.getPeeledObjectId() != null) {
+ float[] colorComponents = g.getBackground().getRGBColorComponents(null);
+ colorComponents[0] *= 0.9;
+ colorComponents[1] *= 0.9;
+ colorComponents[2] *= 0.9;
+ g.setBackground(new Color(colorComponents[0],colorComponents[1],colorComponents[2]));
+ }
+ if (txt.length() > 12)
+ txt = txt.substring(0,11) + "\u2026"; // ellipsis "â¦" (in UTF-8)
+
+ final int texth = g.getFontMetrics().getHeight();
+ int textw = g.getFontMetrics().stringWidth(txt);
+ g.setColor(g.getBackground());
+ int arcHeight = texth/4;
+ int y0 = y - texth/2 + (cell.getHeight() - texth)/2;
+ g.fillRoundRect(x , y0, textw + arcHeight*2, texth -1, arcHeight, arcHeight);
+ g.setColor(g.getColor().darker());
+ g.drawRoundRect(x, y0, textw + arcHeight*2, texth -1 , arcHeight, arcHeight);
+ g.setColor(Color.BLACK);
+ g.drawString(txt, x + arcHeight, y0 + texth - g.getFontMetrics().getDescent());
+
+ return arcHeight * 3 + textw;
+ }
}
\ No newline at end of file
diff --git a/org.spearce.jgit/src/org/spearce/jgit/revplot/AbstractPlotRenderer.java b/org.spearce.jgit/src/org/spearce/jgit/revplot/AbstractPlotRenderer.java
index f175c9d..603547b 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/revplot/AbstractPlotRenderer.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/revplot/AbstractPlotRenderer.java
@@ -37,6 +37,7 @@
package org.spearce.jgit.revplot;
+import org.spearce.jgit.lib.Ref;
import org.spearce.jgit.revwalk.RevFlag;
/**
@@ -140,11 +141,24 @@ protected void paintCommit(final PlotCommit<TLane> commit, final int h) {
else
drawCommitDot(dotX, dotY, dotSize, dotSize);
+ int textx = Math.max(maxCenter + LANE_WIDTH / 2, dotX + dotSize) + 8;
+ int n = commit.refs == null ? 0 : commit.refs.length;
+ for (int i = 0; i < n; ++i) {
+ textx += drawLabel(textx + dotSize, h/2, commit.refs[i]);
+ }
+
final String msg = commit.getShortMessage();
- final int textx = Math.max(maxCenter + LANE_WIDTH / 2, dotX + dotSize) + 8;
- drawText(msg, textx, h / 2);
+ drawText(msg, textx + dotSize + n*2, h / 2);
}
+ /** FIXME: supply text
+ * @param x
+ * @param y
+ * @param ref TODO
+ * @return TODO
+ */
+ protected abstract int drawLabel(int x, int y, Ref ref);
+
private int computeDotSize(final int h) {
int d = (int) (Math.min(h, LANE_WIDTH) * 0.50f);
d += (d & 1);
diff --git a/org.spearce.jgit/src/org/spearce/jgit/revplot/PlotCommit.java b/org.spearce.jgit/src/org/spearce/jgit/revplot/PlotCommit.java
index 5a5ef1e..fac89f5 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/revplot/PlotCommit.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/revplot/PlotCommit.java
@@ -39,6 +39,7 @@
import org.spearce.jgit.lib.AnyObjectId;
import org.spearce.jgit.revwalk.RevCommit;
+import org.spearce.jgit.lib.Ref;
/**
* A commit reference to a commit in the DAG.
@@ -58,14 +59,19 @@
PlotCommit[] children;
+ Ref[] refs;
+
/**
* Create a new commit.
*
* @param id
* the identity of this commit.
+ * @param tags
+ * the tags associated with this commit, null for no tags
*/
- protected PlotCommit(final AnyObjectId id) {
+ protected PlotCommit(final AnyObjectId id, final Ref[] tags) {
super(id);
+ this.refs = tags;
passingLanes = NO_LANES;
children = NO_CHILDREN;
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/revplot/PlotWalk.java b/org.spearce.jgit/src/org/spearce/jgit/revplot/PlotWalk.java
index e5e8aba..6e253f4 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/revplot/PlotWalk.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/revplot/PlotWalk.java
@@ -37,14 +37,26 @@
package org.spearce.jgit.revplot;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
import org.spearce.jgit.lib.AnyObjectId;
+import org.spearce.jgit.lib.Commit;
+import org.spearce.jgit.lib.Ref;
import org.spearce.jgit.lib.Repository;
+import org.spearce.jgit.lib.Tag;
import org.spearce.jgit.revwalk.RevCommit;
import org.spearce.jgit.revwalk.RevSort;
import org.spearce.jgit.revwalk.RevWalk;
/** Specialized RevWalk for visualization of a commit graph. */
public class PlotWalk extends RevWalk {
+
+ Map<AnyObjectId, List<Ref>> reverseRefMap;
+
/**
* Create a new revision walker for a given repository.
*
@@ -54,6 +66,7 @@
public PlotWalk(final Repository repo) {
super(repo);
super.sort(RevSort.TOPO, true);
+ reverseRefMap = repo.getAllRefsByPeeledObjectId();
}
@Override
@@ -64,7 +77,46 @@ public void sort(final RevSort s, final boolean use) {
}
@Override
- protected RevCommit createCommit(final AnyObjectId id) {
- return new PlotCommit(id);
+ protected RevCommit createCommit(final AnyObjectId id, final Ref[] tags) {
+ return new PlotCommit(id, tags);
+ }
+
+ @Override
+ protected Ref[] getTags(final AnyObjectId commitId) {
+ List<Ref> list = reverseRefMap.get(commitId);
+ Ref[] tags;
+ if (list == null)
+ tags = null;
+ else {
+ if (list != null && list.size() > 1) {
+ Collections.sort(list, new Comparator<Ref>() {
+ public int compare(Ref o1, Ref o2) {
+ try {
+ Object obj1 = getRepository().mapObject(o1.getObjectId(), o1.getName());
+ Object obj2 = getRepository().mapObject(o2.getObjectId(), o2.getName());
+ long t1 = timeof(obj1);
+ long t2 = timeof(obj2);
+ if (t1 > t2)
+ return -1;
+ if (t1 < t2)
+ return 1;
+ return 0;
+ } catch (IOException e) {
+ // ignore
+ return 0;
+ }
+ }
+ long timeof(Object o) {
+ if (o instanceof Commit)
+ return ((Commit)o).getCommitter().getWhen().getTime();
+ if (o instanceof Tag)
+ return ((Tag)o).getTagger().getWhen().getTime();
+ return 0;
+ }
+ });
+ }
+ tags = list.toArray(new Ref[list.size()]);
+ }
+ return tags;
}
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java b/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java
index d7e4c58..41d57c6 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java
@@ -53,6 +53,7 @@
import org.spearce.jgit.lib.ObjectId;
import org.spearce.jgit.lib.ObjectIdSubclassMap;
import org.spearce.jgit.lib.ObjectLoader;
+import org.spearce.jgit.lib.Ref;
import org.spearce.jgit.lib.Repository;
import org.spearce.jgit.lib.WindowCursor;
import org.spearce.jgit.revwalk.filter.RevFilter;
@@ -541,7 +542,7 @@ public RevTree lookupTree(final AnyObjectId id) {
public RevCommit lookupCommit(final AnyObjectId id) {
RevCommit c = (RevCommit) objects.get(id);
if (c == null) {
- c = createCommit(id);
+ c = createCommit(id, getTags(id));
objects.add(c);
}
return c;
@@ -564,7 +565,7 @@ public RevObject lookupAny(final AnyObjectId id, final int type) {
if (r == null) {
switch (type) {
case Constants.OBJ_COMMIT:
- r = createCommit(id);
+ r = createCommit(id, getTags(id));
break;
case Constants.OBJ_TREE:
r = new RevTree(id);
@@ -687,7 +688,7 @@ public RevObject parseAny(final AnyObjectId id)
final int type = ldr.getType();
switch (type) {
case Constants.OBJ_COMMIT: {
- final RevCommit c = createCommit(ldr.getId());
+ final RevCommit c = createCommit(ldr.getId(), getTags(ldr.getId()));
c.parseCanonical(this, data);
r = c;
break;
@@ -718,6 +719,14 @@ public RevObject parseAny(final AnyObjectId id)
}
/**
+ * @param commitId
+ * @return the list of refs associated with a commit, possibly filtered
+ */
+ protected Ref[] getTags(final AnyObjectId commitId) {
+ return null; // Don't get tags in the basic case
+ }
+
+ /**
* Ensure the object's content has been parsed.
* <p>
* This method only returns successfully if the object exists and was parsed
@@ -1008,9 +1017,11 @@ private boolean isNotStarted() {
*
* @param id
* the object this walker requires a commit reference for.
+ * @param tags
+ * tags attached to the commit
* @return a new unparsed reference for the object.
*/
- protected RevCommit createCommit(final AnyObjectId id) {
+ protected RevCommit createCommit(final AnyObjectId id, final Ref[] tags) {
return new RevCommit(id);
}
--
1.6.0.1.310.gf789d0.dirty
^ permalink raw reply related
* [EGIT PATCH 1/6] Keep original ref name when reading refs
From: Robin Rosenberg @ 2008-10-05 23:36 UTC (permalink / raw)
To: git; +Cc: spearce, Robin Rosenberg
In-Reply-To: <1223249802-9959-1-git-send-email-robin.rosenberg@dewire.com>
We want to know the original name of refs, not just the target name.
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
org.spearce.jgit/src/org/spearce/jgit/lib/Ref.java | 63 +++++++++++++++++++-
.../src/org/spearce/jgit/lib/RefDatabase.java | 45 +++++++++-----
.../src/org/spearce/jgit/lib/RefUpdate.java | 14 ++---
3 files changed, 94 insertions(+), 28 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Ref.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Ref.java
index db94875..2f102af 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Ref.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Ref.java
@@ -43,6 +43,11 @@
* A ref in Git is (more or less) a variable that holds a single object
* identifier. The object identifier can be any valid Git object (blob, tree,
* commit, annotated tag, ...).
+ * <p>
+ * The ref name has the attributes of the ref that was asked for as well as
+ * the ref it was resolved to for symbolic refs plus the object id it points
+ * to and (for tags) the peeled target object id, i.e. the tag resolved
+ * recursively until a non-tag object is referenced.
*/
public class Ref {
/** Location where a {@link Ref} is stored. */
@@ -119,19 +124,24 @@ public boolean isPacked() {
private ObjectId peeledObjectId;
+ private final String origName;
+
/**
* Create a new ref pairing.
*
* @param st
* method used to store this ref.
+ * @param origName
+ * The name used to resolve this ref
* @param refName
* name of this ref.
* @param id
* current value of the ref. May be null to indicate a ref that
* does not exist yet.
*/
- public Ref(final Storage st, final String refName, final ObjectId id) {
+ public Ref(final Storage st, final String origName, final String refName, final ObjectId id) {
storage = st;
+ this.origName = origName;
name = refName;
objectId = id;
}
@@ -146,19 +156,56 @@ public Ref(final Storage st, final String refName, final ObjectId id) {
* @param id
* current value of the ref. May be null to indicate a ref that
* does not exist yet.
+ */
+ public Ref(final Storage st, final String refName, final ObjectId id) {
+ this(st, refName, refName, id);
+ }
+
+ /**
+ * Create a new ref pairing.
+ *
+ * @param st
+ * method used to store this ref.
+ * @param origName
+ * The name used to resolve this ref
+ * @param refName
+ * name of this ref.
+ * @param id
+ * current value of the ref. May be null to indicate a ref that
+ * does not exist yet.
* @param peel
* peeled value of the ref's tag. May be null if this is not a
* tag or the peeled value is not known.
*/
- public Ref(final Storage st, final String refName, final ObjectId id,
+ public Ref(final Storage st, final String origName, final String refName, final ObjectId id,
final ObjectId peel) {
storage = st;
+ this.origName = origName;
name = refName;
objectId = id;
peeledObjectId = peel;
}
/**
+ * Create a new ref pairing.
+ *
+ * @param st
+ * method used to store this ref.
+ * @param refName
+ * name of this ref.
+ * @param id
+ * current value of the ref. May be null to indicate a ref that
+ * does not exist yet.
+ * @param peel
+ * peeled value of the ref's tag. May be null if this is not a
+ * tag or the peeled value is not known.
+ */
+ public Ref(final Storage st, final String refName, final ObjectId id,
+ final ObjectId peel) {
+ this(st, refName, refName, id, peel);
+ }
+
+ /**
* What this ref is called within the repository.
*
* @return name of this ref.
@@ -168,6 +215,13 @@ public String getName() {
}
/**
+ * @return the originally resolved name
+ */
+ public String getOrigName() {
+ return origName;
+ }
+
+ /**
* Cached value of this ref.
*
* @return the value of this ref at the last time we read it.
@@ -200,6 +254,9 @@ public Storage getStorage() {
}
public String toString() {
- return "Ref[" + name + "=" + ObjectId.toString(getObjectId()) + "]";
+ String o = "";
+ if (!origName.equals(name))
+ o = "(" + origName + ")";
+ return "Ref[" + o + name + "=" + ObjectId.toString(getObjectId()) + "]";
}
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
index 5c1f060..5a1b85f 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
@@ -51,6 +51,7 @@
import java.util.Map;
import org.spearce.jgit.errors.ObjectWritingException;
+import org.spearce.jgit.lib.Ref.Storage;
import org.spearce.jgit.util.FS;
import org.spearce.jgit.util.NB;
@@ -135,8 +136,8 @@ RefUpdate newUpdate(final String name) throws IOException {
return new RefUpdate(this, r, fileForRef(r.getName()));
}
- void stored(final String name, final ObjectId id, final long time) {
- looseRefs.put(name, new Ref(Ref.Storage.LOOSE, name, id));
+ void stored(final String origName, final String name, final ObjectId id, final long time) {
+ looseRefs.put(name, new Ref(Ref.Storage.LOOSE, origName, name, id));
looseRefsMTime.put(name, time);
setModified();
db.fireRefsMaybeChanged();
@@ -222,12 +223,12 @@ private void readLooseRefs(final Map<String, Ref> avail,
final String entName = ent.getName();
if (".".equals(entName) || "..".equals(entName))
continue;
- readOneLooseRef(avail, prefix + entName, ent);
+ readOneLooseRef(avail, prefix + entName, prefix + entName, ent);
}
}
private void readOneLooseRef(final Map<String, Ref> avail,
- final String refName, final File ent) {
+ final String origName, final String refName, final File ent) {
// Unchanged and cached? Don't read it again.
//
Ref ref = looseRefs.get(refName);
@@ -270,7 +271,7 @@ private void readOneLooseRef(final Map<String, Ref> avail,
return;
}
- ref = new Ref(Ref.Storage.LOOSE, refName, id);
+ ref = new Ref(Ref.Storage.LOOSE, origName, refName, id);
looseRefs.put(ref.getName(), ref);
looseRefsMTime.put(ref.getName(), ent.lastModified());
avail.put(ref.getName(), ref);
@@ -293,27 +294,35 @@ private File fileForRef(final String name) {
return new File(gitDir, name);
}
- private Ref readRefBasic(final String name, final int depth)
+ private Ref readRefBasic(final String name, final int depth) throws IOException {
+ return readRefBasic(name, name, depth);
+ }
+
+ private Ref readRefBasic(final String origName, final String name, final int depth)
throws IOException {
// Prefer loose ref to packed ref as the loose
// file can be more up-to-date than a packed one.
//
- Ref ref = looseRefs.get(name);
+ Ref ref = looseRefs.get(origName);
final File loose = fileForRef(name);
final long mtime = loose.lastModified();
if (ref != null) {
Long cachedlastModified = looseRefsMTime.get(name);
if (cachedlastModified != null && cachedlastModified == mtime)
return ref;
- looseRefs.remove(name);
- looseRefsMTime.remove(name);
+ looseRefs.remove(origName);
+ looseRefsMTime.remove(origName);
}
if (mtime == 0) {
// If last modified is 0 the file does not exist.
// Try packed cache.
//
- return packedRefs.get(name);
+ ref = packedRefs.get(name);
+ if (ref != null)
+ if (!ref.getOrigName().equals(origName))
+ ref = new Ref(Storage.LOOSE_PACKED, origName, name, ref.getObjectId());
+ return ref;
}
final String line;
@@ -324,7 +333,7 @@ private Ref readRefBasic(final String name, final int depth)
}
if (line == null || line.length() == 0)
- return new Ref(Ref.Storage.LOOSE, name, null);
+ return new Ref(Ref.Storage.LOOSE, origName, name, null);
if (line.startsWith("ref: ")) {
if (depth >= 5) {
@@ -333,12 +342,16 @@ private Ref readRefBasic(final String name, final int depth)
}
final String target = line.substring("ref: ".length());
- final Ref r = readRefBasic(target, depth + 1);
+ Ref r = readRefBasic(target, target, depth + 1);
Long cachedMtime = looseRefsMTime.get(name);
if (cachedMtime != null && cachedMtime != mtime)
setModified();
looseRefsMTime.put(name, mtime);
- return r != null ? r : new Ref(Ref.Storage.LOOSE, target, null);
+ if (r == null)
+ return new Ref(Ref.Storage.LOOSE, origName, target, null);
+ if (!origName.equals(r.getName()))
+ r = new Ref(Ref.Storage.LOOSE_PACKED, origName, r.getName(), r.getObjectId(), r.getPeeledObjectId());
+ return r;
}
setModified();
@@ -350,7 +363,7 @@ private Ref readRefBasic(final String name, final int depth)
throw new IOException("Not a ref: " + name + ": " + line);
}
- ref = new Ref(Ref.Storage.LOOSE, name, id);
+ ref = new Ref(Ref.Storage.LOOSE, origName, name, id);
looseRefs.put(name, ref);
looseRefsMTime.put(name, mtime);
return ref;
@@ -384,7 +397,7 @@ private void refreshPackedRefs() {
final ObjectId id = ObjectId.fromString(p.substring(1));
last = new Ref(Ref.Storage.PACKED, last.getName(), last
- .getObjectId(), id);
+ .getName(), last.getObjectId(), id);
newPackedRefs.put(last.getName(), last);
continue;
}
@@ -392,7 +405,7 @@ private void refreshPackedRefs() {
final int sp = p.indexOf(' ');
final ObjectId id = ObjectId.fromString(p.substring(0, sp));
final String name = new String(p.substring(sp + 1));
- last = new Ref(Ref.Storage.PACKED, name, id);
+ last = new Ref(Ref.Storage.PACKED, name, name, id);
newPackedRefs.put(last.getName(), last);
}
} finally {
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java
index 86b44c5..235c2fd 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java
@@ -131,9 +131,6 @@
/** Repository the ref is stored in. */
private final RefDatabase db;
- /** Name of the ref. */
- private final String name;
-
/** Location of the loose file holding the value of this ref. */
private final File looseFile;
@@ -160,7 +157,6 @@
RefUpdate(final RefDatabase r, final Ref ref, final File f) {
db = r;
this.ref = ref;
- name = ref.getName();
oldValue = ref.getObjectId();
looseFile = f;
}
@@ -171,7 +167,7 @@ RefUpdate(final RefDatabase r, final Ref ref, final File f) {
* @return name of this ref.
*/
public String getName() {
- return name;
+ return ref.getName();
}
/**
@@ -349,9 +345,9 @@ public Result delete() throws IOException {
* @throws IOException
*/
public Result delete(final RevWalk walk) throws IOException {
- if (name.startsWith(Constants.R_HEADS)) {
+ if (getName().startsWith(Constants.R_HEADS)) {
final Ref head = db.readRef(Constants.HEAD);
- if (head != null && name.equals(head.getName()))
+ if (head != null && getName().equals(head.getName()))
return Result.REJECTED_CURRENT_BRANCH;
}
@@ -373,7 +369,7 @@ private Result updateImpl(final RevWalk walk, final Store store)
if (!lock.lock())
return Result.LOCK_FAILURE;
try {
- oldValue = db.idOf(name);
+ oldValue = db.idOf(getName());
if (oldValue == null)
return store.store(lock, Result.NEW);
@@ -428,7 +424,7 @@ else if (status == Result.NEW)
getName());
if (!lock.commit())
return Result.LOCK_FAILURE;
- db.stored(name, newValue, lock.getCommitLastModified());
+ db.stored(this.ref.getOrigName(), ref.getName(), newValue, lock.getCommitLastModified());
return status;
}
--
1.6.0.1.310.gf789d0.dirty
^ permalink raw reply related
* [EGIT PATCH 5/6] Add decorate option to log program
From: Robin Rosenberg @ 2008-10-05 23:36 UTC (permalink / raw)
To: git; +Cc: spearce, Robin Rosenberg
In-Reply-To: <1223249802-9959-5-git-send-email-robin.rosenberg@dewire.com>
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
.../src/org/spearce/jgit/pgm/Log.java | 32 ++++++++++++++++++++
1 files changed, 32 insertions(+), 0 deletions(-)
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Log.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Log.java
index e16387b..378d9e0 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Log.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Log.java
@@ -40,10 +40,17 @@
import java.text.DateFormat;
import java.text.SimpleDateFormat;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import java.util.TimeZone;
+import org.kohsuke.args4j.Option;
+import org.spearce.jgit.lib.AnyObjectId;
import org.spearce.jgit.lib.PersonIdent;
+import org.spearce.jgit.lib.Ref;
import org.spearce.jgit.revwalk.RevCommit;
+import org.spearce.jgit.revwalk.RevWalk;
@Command(common = true, usage = "View commit history")
class Log extends RevWalkTextBuiltin {
@@ -51,14 +58,39 @@
private final DateFormat fmt;
+ private Map<AnyObjectId, List<Ref>> allRefsByPeeledObjectId;
+
+ @Option(name="--decorate", usage="Show ref names matching commits")
+ private boolean decorate;
+
Log() {
fmt = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZZZZ");
}
@Override
+ protected org.spearce.jgit.revwalk.RevWalk createWalk() {
+ RevWalk ret = super.createWalk();
+ if (decorate)
+ allRefsByPeeledObjectId = getRepository().getAllRefsByPeeledObjectId();
+ return ret;
+ }
+
+ @Override
protected void show(final RevCommit c) throws Exception {
out.print("commit ");
c.getId().copyTo(outbuffer, out);
+ if (decorate) {
+ List<Ref> list = allRefsByPeeledObjectId.get(c.copy());
+ if (list != null) {
+ out.print(" (");
+ for (Iterator<Ref> i = list.iterator(); i.hasNext(); ) {
+ out.print(i.next().getOrigName());
+ if (i.hasNext())
+ out.print(" ");
+ }
+ out.print(")");
+ }
+ }
out.println();
final PersonIdent author = c.getAuthorIdent();
--
1.6.0.1.310.gf789d0.dirty
^ permalink raw reply related
* [EGIT PATCH 3/6] Add a method to get refs by object Id
From: Robin Rosenberg @ 2008-10-05 23:36 UTC (permalink / raw)
To: git; +Cc: spearce, Robin Rosenberg
In-Reply-To: <1223249802-9959-3-git-send-email-robin.rosenberg@dewire.com>
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
.../src/org/spearce/jgit/lib/Repository.java | 28 ++++++++++++++++++++
1 files changed, 28 insertions(+), 0 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
index dfce1b8..3fc5236 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
@@ -47,6 +47,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -939,6 +940,33 @@ public String getBranch() throws IOException {
}
/**
+ * @return a map with all objects referenced by a peeled ref.
+ */
+ public Map<AnyObjectId, List<Ref>> getAllRefsByPeeledObjectId() {
+ Map<String, Ref> allRefs = getAllRefs();
+ HashMap<AnyObjectId, List<Ref>> ret = new HashMap<AnyObjectId, List<Ref>>(allRefs.size());
+ for (Map.Entry<String,Ref> e : allRefs.entrySet()) {
+ Ref ref = e.getValue();
+ AnyObjectId target = ref.getPeeledObjectId();
+ if (target == null)
+ target = ref.getObjectId();
+ List<Ref> list = ret.get(target);
+ if (list == null) {
+ list = Collections.singletonList(ref);
+ } else {
+ if (list.size() == 1) {
+ ArrayList<Ref> list2 = new ArrayList<Ref>(2);
+ list2.add(list.get(0));
+ list = list2;
+ }
+ list.add(ref);
+ }
+ ret.put(target, list);
+ }
+ return ret;
+ }
+
+ /**
* @return true if HEAD points to a StGit patch.
*/
public boolean isStGitMode() {
--
1.6.0.1.310.gf789d0.dirty
^ permalink raw reply related
* [EGIT PATCH 2/6] Peel annotated tags when getting all refs
From: Robin Rosenberg @ 2008-10-05 23:36 UTC (permalink / raw)
To: git; +Cc: spearce, Robin Rosenberg
In-Reply-To: <1223249802-9959-2-git-send-email-robin.rosenberg@dewire.com>
For packed refs we got this automatically from packed-refs,
but for loose tags we have to follow the tags and get the leaf
object in order to comply with the documentation.
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
.../src/org/spearce/jgit/lib/RefDatabase.java | 24 ++++++++++++++++++-
1 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
index 5a1b85f..1ee70d9 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
@@ -271,7 +271,16 @@ private void readOneLooseRef(final Map<String, Ref> avail,
return;
}
- ref = new Ref(Ref.Storage.LOOSE, origName, refName, id);
+ Object tt = db.mapObject(id, refName);
+ if (tt != null && tt instanceof Tag) {
+ Tag t = (Tag)tt;
+ while (t != null && t.getType().equals(Constants.TYPE_TAG))
+ t = db.mapTag(t.getTag(), t.getObjId());
+ if (t != null)
+ ref = new Ref(Ref.Storage.LOOSE, origName, refName, id, t.getObjId());
+ } else
+ ref = new Ref(Ref.Storage.LOOSE, origName, refName, id);
+
looseRefs.put(ref.getName(), ref);
looseRefsMTime.put(ref.getName(), ent.lastModified());
avail.put(ref.getName(), ref);
@@ -363,7 +372,18 @@ private Ref readRefBasic(final String origName, final String name, final int dep
throw new IOException("Not a ref: " + name + ": " + line);
}
- ref = new Ref(Ref.Storage.LOOSE, origName, name, id);
+ Object tt = db.mapObject(id, origName);
+ if (tt != null && tt instanceof Tag) {
+ Tag t = (Tag)tt;
+ while (t != null && t.getType().equals(Constants.TYPE_TAG))
+ t = db.mapTag(t.getTag(), t.getObjId());
+ if (t != null)
+ ref = new Ref(Ref.Storage.LOOSE, origName, name, id, t.getObjId());
+ } else
+ ref = new Ref(Ref.Storage.LOOSE, origName, name, id);
+
+ looseRefs.put(origName, ref);
+ ref = new Ref(Ref.Storage.LOOSE, origName, id);
looseRefs.put(name, ref);
looseRefsMTime.put(name, mtime);
return ref;
--
1.6.0.1.310.gf789d0.dirty
^ permalink raw reply related
* [EGIT PATCH 6/6] Comment the getId method and hint for copy to actually get an ObjectId
From: Robin Rosenberg @ 2008-10-05 23:36 UTC (permalink / raw)
To: git; +Cc: spearce, Robin Rosenberg
In-Reply-To: <1223249802-9959-6-git-send-email-robin.rosenberg@dewire.com>
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
.../src/org/spearce/jgit/revwalk/RevObject.java | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevObject.java b/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevObject.java
index 451205c..2209c04 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevObject.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevObject.java
@@ -67,6 +67,7 @@ abstract void parse(RevWalk walk) throws MissingObjectException,
/**
* Get the name of this object.
+ * See {@link #copy()} to really get a copy
*
* @return unique hash of this object.
*/
--
1.6.0.1.310.gf789d0.dirty
^ permalink raw reply related
* (unknown),
From: Robin Rosenberg @ 2008-10-05 23:36 UTC (permalink / raw)
To: git; +Cc: spearce
This series decorates the graphical and text (jgit log) history listings
with tags. For the text command it is optional.
Reviewers may want to pay special attention to the changes in the Ref class.
-- robin
^ permalink raw reply
* RE: gitweb improvements
From: Tjernlund @ 2008-10-05 22:25 UTC (permalink / raw)
To: 'Jakub Narebski'; +Cc: 'git'
In-Reply-To: <m34p3rq7og.fsf@localhost.localdomain>
> -----Original Message-----
> From: Jakub Narebski [mailto:jnareb@gmail.com]
> Sent: den 5 oktober 2008 19:22
> To: Tjernlund
> Cc: 'git'
> Subject: Re: gitweb improvements
>
> "Tjernlund" <tjernlund@tjernlund.se> writes:
>
> > When I browse a repo using gitweb, I miss two things:
> > 1) looking at the history for a file or directory I really want
> > to see the tags there too.
>
> Should be easy to do, but would probably wait (and be indirect result)
> of refactoring/unification of log-like views code ('log', 'shortlog',
> 'history', perhaps also 'rss', 'atom', 'search')
>
> I have added it to my gitweb TODO list...
Great! Thanks.
>
> > 2) looking at a merge like:
> > http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-
> 2.6.git;a=commit;h=66120005e65eed8a05b14a36ab448bdec42f0d6b
> > is somewhat confusing. It really doesn't tell you which commits that is
> > included in the merge.
>
> I don't understand you there. First, you have "(merge: 0d0f3ef 9778e9a)"
> in the navbar, so you can easily go to commit view for parents. Second,
> among commit headers you have two "parent", where SHA-1 of a commit is
> hidden link, and there are also 'commit' and 'diff' link for those.
hmm, looks like I overlooked "(merge: 0d0f3ef 9778e9a)" part. However, I can't
find the "ALSA: make the CS4270 driver a new-style I2C driver" from within
this page.
>
> --
> Jakub Narebski
> Poland
> ShadeHawk on #git
^ permalink raw reply
* Re: [ANNOUNCE] cgit 0.8
From: Lars Hjemli @ 2008-10-05 22:22 UTC (permalink / raw)
To: Asheesh Laroia; +Cc: Git Mailing List
In-Reply-To: <alpine.DEB.2.00.0810051346290.27691@alchemy.localdomain>
On Sun, Oct 5, 2008 at 22:49, Asheesh Laroia <git@asheesh.org> wrote:
> On Sun, 5 Oct 2008, Lars Hjemli wrote:
>
>> cgit-0.8, another webinterface for git, is now available.
>>
> I'm curious - is there any interest in the cgit world in providing gitweb
> URL compatibility?
Well, it's a request that's popped up a few times, but no patches so
far. It would probably be a nice feature if it could be done cleanly.
> Either way, thanks a bundle to all who work on cgit! (And is this the
> canonical place to discuss it?)
You're welcome. And yes, I think this is the place (cgit doesn't have
a mailinglist of its own).
--
larsh
^ permalink raw reply
* Re: [PATCH 2] renaming git add -i [r]evert -> reset and adding gitt add -i [c]heckout
From: Jeff King @ 2008-10-05 22:11 UTC (permalink / raw)
To: Marc Weber; +Cc: git
In-Reply-To: <20081005214644.GB32727@gmx.de>
On Sun, Oct 05, 2008 at 11:46:44PM +0200, Marc Weber wrote:
> I'll try to do it better now (not sure who is the mantainer though,
> I've seen that you've commited some lines to this file)..
The usual git maintainer is Junio Hamano <gitster@pobox.com>.
But he is out of touch for a few weeks, so the interim maintainer is
Shawn Pearce <spearce@spearce.org>.
> ============= attachement git show output ============================
The usual way of mailing patches is a bit different:
- send one patch per email; if multiple patches are meant to be applied
in series, number them [PATCH i/n]. In this case, I think you would
want your patches applied in series (since the second one will
textually depend on the first).
- use "git format-patch" to generate the patches. This generates an
email format that can be applied on the other end by "git am".
- use "git send-email" to send the patches generated by format-patch.
You can also send the patches directly from your mail reader, but you
will want to merge your regular mail headers with those generated by
format-patch (e.g., the Subject line generated by format-patch should
become the subject line of your message).
> commit 852b21bf88b1de784244a6e99de9a53a5c61dd8c
> Author: Marc Weber <marco-oweber@gmx.de>
> Date: Sun Oct 5 23:09:04 2008 +0200
>
> rename the git add -i [r]evert command to [r]eset to use the same term as in git reset
> purpose: decrease possibility of confusion for users with svn background (svn revert = git checkout)
Please follow the usual "subject\n\nbody" convention for commit
messages. And if the patch touches just one subsystem, we usually say
"subsystem: what the patch does." So something like:
add--interactive: rename [r]evert command to [r]eset
followed by a newline, then your explanation.
I think you may want to note on this patch, too, that "revert" is also
confusing for git users. Maybe like:
The term "revert" is used very confusingly here. In git, to "revert"
is to take the changes made by a previous commit and un-apply them,
creating a new commit. The act of changing what is in the index to
match HEAD is called "reset".
Furthermore, incoming svn users will also find this confusing, since
to them, "revert" means to reset the working tree, which corresponds
to "checkout" in git.
> commit b3d438764a7429e1dfacef8f499a0126076ed2bc
> Author: Marc Weber <marco-oweber@gmx.de>
> Date: Sun Oct 5 15:15:38 2008 +0000
>
> renamed revert in ga -i to reset, added [c]heckout
The first patch has been split out, and then this one contains the
changes for both. So I think what you want to do is to rebase this
change on top of the previous one, so that it should then have just the
"checkout" changes, and then write an appropriate commit message for it.
-Peff
^ permalink raw reply
* Re: [PATCH 0/4] diff text conversion filter
From: Jakub Narebski @ 2008-10-05 22:03 UTC (permalink / raw)
To: git
In-Reply-To: <20081005214114.GA21875@coredump.intra.peff.net>
Jeff King wrote:
> On Tue, Sep 30, 2008 at 12:45:45PM -0400, Jeff King wrote:
>
>> I am about 90% done cleaning it up for preparation (there is a bit of
>> refactoring, and I want to make sure I get that just right). I'll post
>> it in the next day or so.
>
> Sorry, I didn't get a chance to look at this until today. Patch series
> will follow. It is still missing documentation updates and tests, but I
> wanted to get you something to look at (and as I am proposing a new
> meaning for "diff driver", I would be curious to hear the general
> comments).
>
> This is on top of 'next', because it would otherwise conflict with the
> funcname pattern changes there.
Documentation, pretty please?
--
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
^ permalink raw reply
* [PATCH 2] renaming git add -i [r]evert -> reset and adding gitt add -i [c]heckout
From: Marc Weber @ 2008-10-05 21:46 UTC (permalink / raw)
To: git
In-Reply-To: <20081005164124.GA31903@coredump.intra.peff.net>
Hi Jeff, thanks!
I'll try to do it better now (not sure who is the mantainer though, I've
seen that you've commited some lines to this file)..
Both patches apply cleanly against c427559 (master).
You can push enhancements directly to
git://mawercer.de/git_my_patches
topic branches:
renaming_revert_to_reset
revert_to_reset_renaming
Sincerly
Marc Weber
============= attachement git show output ============================
commit 852b21bf88b1de784244a6e99de9a53a5c61dd8c
Author: Marc Weber <marco-oweber@gmx.de>
Date: Sun Oct 5 23:09:04 2008 +0200
rename the git add -i [r]evert command to [r]eset to use the same term as in git reset
purpose: decrease possibility of confusion for users with svn background (svn revert = git checkout)
Signed-off-by: Marc Weber <marco-oweber@gmx.de>
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index da768ee..5352d16 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -498,8 +498,8 @@ sub update_cmd {
print "\n";
}
-sub revert_cmd {
- my @update = list_and_choose({ PROMPT => 'Revert',
+sub reset_cmd {
+ my @update = list_and_choose({ PROMPT => 'Reset',
HEADER => $status_head, },
list_modified());
if (@update) {
@@ -527,7 +527,7 @@ sub revert_cmd {
}
}
refresh();
- say_n_paths('reverted', @update);
+ say_n_paths('reset', @update);
}
print "\n";
}
@@ -1046,7 +1046,7 @@ sub help_cmd {
print colored $help_color, <<\EOF ;
status - show paths with changes
update - add working tree state to the staged set of changes
-revert - revert staged set of changes back to the HEAD version
+reset - reset staged set of changes back to the HEAD version
patch - pick hunks and update selectively
diff - view diff between HEAD and index
add untracked - add contents of untracked files to the staged set of changes
@@ -1070,7 +1070,7 @@ sub process_args {
sub main_loop {
my @cmd = ([ 'status', \&status_cmd, ],
[ 'update', \&update_cmd, ],
- [ 'revert', \&revert_cmd, ],
+ [ 'reset', \&reset_cmd, ],
[ 'add untracked', \&add_untracked_cmd, ],
[ 'patch', \&patch_update_cmd, ],
[ 'diff', \&diff_cmd, ],
commit b3d438764a7429e1dfacef8f499a0126076ed2bc
Author: Marc Weber <marco-oweber@gmx.de>
Date: Sun Oct 5 15:15:38 2008 +0000
renamed revert in ga -i to reset, added [c]heckout
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index da768ee..32c300f 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -498,8 +498,8 @@ sub update_cmd {
print "\n";
}
-sub revert_cmd {
- my @update = list_and_choose({ PROMPT => 'Revert',
+sub reset_cmd {
+ my @update = list_and_choose({ PROMPT => 'Reset',
HEADER => $status_head, },
list_modified());
if (@update) {
@@ -527,7 +527,31 @@ sub revert_cmd {
}
}
refresh();
- say_n_paths('reverted', @update);
+ say_n_paths('reset', @update);
+ }
+ print "\n";
+}
+
+sub checkout_cmd {
+ my @update = list_and_choose({ PROMPT => 'Checkout',
+ HEADER => $status_head, },
+ list_modified());
+ if (@update) {
+ if (is_initial_commit()) {
+ # should never be executed because there can't
be modified files
+ print "error: no revision in repo yet\n";
+ }
+ else {
+ for (@update) {
+ if ($_->{INDEX_ADDDEL} &&
+ $_->{INDEX_ADDDEL} eq 'create') {
+ system(qw(git checkout --),
+ $_->{VALUE});
+ }
+ }
+ }
+ refresh();
+ say_n_paths('checked out', @update);
}
print "\n";
}
@@ -1046,7 +1070,8 @@ sub help_cmd {
print colored $help_color, <<\EOF ;
status - show paths with changes
update - add working tree state to the staged set of changes
-revert - revert staged set of changes back to the HEAD version
+reset - reset staged set of changes back to the HEAD version
+checkout - reset working copy file back to the HEAD version
patch - pick hunks and update selectively
diff - view diff between HEAD and index
add untracked - add contents of untracked files to the staged set of
changes
@@ -1070,7 +1095,8 @@ sub process_args {
sub main_loop {
my @cmd = ([ 'status', \&status_cmd, ],
[ 'update', \&update_cmd, ],
- [ 'revert', \&revert_cmd, ],
+ [ 'reset', \&reset_cmd, ],
+ [ 'checkout', \&checkout_cmd, ],
[ 'add untracked', \&add_untracked_cmd, ],
[ 'patch', \&patch_update_cmd, ],
[ 'diff', \&diff_cmd, ],
^ permalink raw reply related
* [PATCH 4/4] diff: add filter for converting binary to text
From: Jeff King @ 2008-10-05 21:43 UTC (permalink / raw)
To: Matthieu Moy; +Cc: git
In-Reply-To: <20081005214114.GA21875@coredump.intra.peff.net>
When diffing binary files, it is sometimes nice to see the
differences of a canonical text form rather than either a
binary patch or simply "binary files differ."
Until now, the only option for doing this was to define an
external diff command to perform the diff. This was a lot of
work, since the external command needed to take care of
doing the diff itself (including mode changes), and lost the
benefit of git's colorization and other options.
This patch adds a text conversion option, which converts a
file to its canonical format before performing the diff.
This is less flexible than an arbitrary external diff, but
is much less work to set up. For example:
$ echo '*.jpg diff=exif' >>.gitattributes
$ git config diff.exif.textconv exiftool
$ git config diff.exif.binary false
allows one to see jpg diffs represented by the text output
of exiftool.
Signed-off-by: Jeff King <peff@peff.net>
---
diff.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++--
userdiff.c | 2 ++
userdiff.h | 1 +
3 files changed, 50 insertions(+), 2 deletions(-)
diff --git a/diff.c b/diff.c
index ba4f6fa..421da29 100644
--- a/diff.c
+++ b/diff.c
@@ -38,6 +38,9 @@ static char diff_colors[][COLOR_MAXLEN] = {
"\033[41m", /* WHITESPACE (red background) */
};
+static void diff_filespec_load_driver(struct diff_filespec *one);
+static char *run_textconv(const char *, struct diff_filespec *, size_t *);
+
static int parse_diff_color_slot(const char *var, int ofs)
{
if (!strcasecmp(var+ofs, "plain"))
@@ -291,8 +294,19 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
}
else if (diff_populate_filespec(one, 0))
return -1;
- mf->ptr = one->data;
- mf->size = one->size;
+
+ diff_filespec_load_driver(one);
+ if (one->driver->textconv) {
+ size_t size;
+ mf->ptr = run_textconv(one->driver->textconv, one, &size);
+ if (!mf->ptr)
+ return -1;
+ mf->size = size;
+ }
+ else {
+ mf->ptr = one->data;
+ mf->size = one->size;
+ }
return 0;
}
@@ -3374,3 +3388,34 @@ void diff_unmerge(struct diff_options *options,
fill_filespec(one, sha1, mode);
diff_queue(&diff_queued_diff, one, two)->is_unmerged = 1;
}
+
+static char *run_textconv(const char *pgm, struct diff_filespec *spec,
+ size_t *outsize)
+{
+ struct diff_tempfile temp;
+ const char *argv[3];
+ const char **arg = argv;
+ struct child_process child;
+ struct strbuf buf = STRBUF_INIT;
+
+ prepare_temp_file(spec->path, &temp, spec);
+ *arg++ = pgm;
+ *arg++ = temp.name;
+ *arg = NULL;
+
+ memset(&child, 0, sizeof(child));
+ child.argv = argv;
+ child.out = -1;
+ if (start_command(&child) != 0 ||
+ strbuf_read(&buf, child.out, 0) < 0 ||
+ finish_command(&child) != 0) {
+ if (temp.name == temp.tmp_path)
+ unlink(temp.name);
+ error("error running textconv command '%s'", pgm);
+ return NULL;
+ }
+ if (temp.name == temp.tmp_path)
+ unlink(temp.name);
+
+ return strbuf_detach(&buf, outsize);
+}
diff --git a/userdiff.c b/userdiff.c
index ac6d4a1..02f225f 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -131,6 +131,8 @@ int userdiff_config_porcelain(const char *k, const char *v)
if ((drv = parse_driver(k, v, "command")))
return parse_string(&drv->external, k, v);
+ if ((drv = parse_driver(k, v, "textconv")))
+ return parse_string(&drv->textconv, k, v);
return 0;
}
diff --git a/userdiff.h b/userdiff.h
index 1c1eb04..f29c18f 100644
--- a/userdiff.h
+++ b/userdiff.h
@@ -11,6 +11,7 @@ struct userdiff_driver {
const char *external;
int binary;
struct userdiff_funcname funcname;
+ const char *textconv;
};
int userdiff_config_basic(const char *k, const char *v);
--
1.6.0.2.639.g4d7f.dirty
^ permalink raw reply related
* [PATCH 3/4] diff: introduce diff.<driver>.binary
From: Jeff King @ 2008-10-05 21:43 UTC (permalink / raw)
To: Matthieu Moy; +Cc: git
In-Reply-To: <20081005214114.GA21875@coredump.intra.peff.net>
The "diff" gitattribute is somewhat overloaded right now. It
can say one of three things:
1. this file is definitely binary, or definitely not
(i.e., diff or !diff)
2. this file should use an external diff engine (i.e.,
diff=foo, diff.foo.command = custom-script)
3. this file should use particular funcname patterns
(i.e., diff=foo, diff.foo.(x?)funcname = some-regex)
Most of the time, there is no conflict between these uses,
since using one implies that the other is irrelevant (e.g.,
an external diff engine will decide for itself whether the
file is binary).
However, there is at least one conflicting situation: there
is no way to say "use the regular rules to determine whether
this file is binary, but if we do diff it textually, use
this funcname pattern." That is, currently setting diff=foo
indicates that the file is definitely text.
This patch introduces a "binary" config option for a diff
driver, so that one can explicitly set diff.foo.binary. We
default this value to "don't know". That is, setting a diff
attribute to "foo" and using "diff.foo.funcname" will have
no effect on the binaryness of a file. To get the current
behavior, one can set diff.foo.binary to true.
This patch also has one additional advantage: it cleans up
the interface to the userdiff code a bit. Before, calling
code had to know more about whether attributes were false,
true, or unset to determine binaryness. Now that binaryness
is a property of a driver, we can represent these situations
just by passing back a driver struct.
Signed-off-by: Jeff King <peff@peff.net>
---
diff.c | 52 ++++++++++++++++++++++------------------------------
diffcore.h | 8 ++++++--
userdiff.c | 19 ++++++++++++++++---
userdiff.h | 4 +---
4 files changed, 45 insertions(+), 38 deletions(-)
diff --git a/diff.c b/diff.c
index 08f335f..ba4f6fa 100644
--- a/diff.c
+++ b/diff.c
@@ -1271,46 +1271,37 @@ static void emit_binary_diff(FILE *file, mmfile_t *one, mmfile_t *two)
emit_binary_diff_body(file, two, one);
}
-static void diff_filespec_check_attr(struct diff_filespec *one)
+void diff_filespec_load_driver(struct diff_filespec *one)
{
- struct userdiff_driver *drv;
- int check_from_data = 0;
-
- if (one->checked_attr)
- return;
-
- drv = userdiff_find_by_path(one->path);
- one->is_binary = 0;
-
- /* binaryness */
- if (drv == USERDIFF_ATTR_TRUE)
- ;
- else if (drv == USERDIFF_ATTR_FALSE)
- one->is_binary = 1;
- else
- check_from_data = 1;
-
- if (check_from_data) {
- if (!one->data && DIFF_FILE_VALID(one))
- diff_populate_filespec(one, 0);
-
- if (one->data)
- one->is_binary = buffer_is_binary(one->data, one->size);
- }
+ if (!one->driver)
+ one->driver = userdiff_find_by_path(one->path);
+ if (!one->driver)
+ one->driver = userdiff_find_by_name("default");
}
int diff_filespec_is_binary(struct diff_filespec *one)
{
- diff_filespec_check_attr(one);
+ if (one->is_binary == -1) {
+ diff_filespec_load_driver(one);
+ if (one->driver->binary != -1)
+ one->is_binary = one->driver->binary;
+ else {
+ if (!one->data && DIFF_FILE_VALID(one))
+ diff_populate_filespec(one, 0);
+ if (one->data)
+ one->is_binary = buffer_is_binary(one->data,
+ one->size);
+ if (one->is_binary == -1)
+ one->is_binary = 0;
+ }
+ }
return one->is_binary;
}
static const struct userdiff_funcname *diff_funcname_pattern(struct diff_filespec *one)
{
- struct userdiff_driver *drv = userdiff_find_by_path(one->path);
- if (!drv)
- drv = userdiff_find_by_name("default");
- return drv && drv->funcname.pattern ? &drv->funcname : NULL;
+ diff_filespec_load_driver(one);
+ return one->driver->funcname.pattern ? &one->driver->funcname : NULL;
}
void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b)
@@ -1558,6 +1549,7 @@ struct diff_filespec *alloc_filespec(const char *path)
spec->path = (char *)(spec + 1);
memcpy(spec->path, path, namelen+1);
spec->count = 1;
+ spec->is_binary = -1;
return spec;
}
diff --git a/diffcore.h b/diffcore.h
index 8ae3578..713cca7 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -22,6 +22,8 @@
#define MINIMUM_BREAK_SIZE 400 /* do not break a file smaller than this */
+struct userdiff_driver;
+
struct diff_filespec {
unsigned char sha1[20];
char *path;
@@ -40,8 +42,10 @@ struct diff_filespec {
#define DIFF_FILE_VALID(spec) (((spec)->mode) != 0)
unsigned should_free : 1; /* data should be free()'ed */
unsigned should_munmap : 1; /* data should be munmap()'ed */
- unsigned checked_attr : 1;
- unsigned is_binary : 1; /* data should be considered "binary" */
+
+ struct userdiff_driver *driver;
+ /* data should be considered "binary"; -1 means "don't know yet" */
+ int is_binary;
};
extern struct diff_filespec *alloc_filespec(const char *);
diff --git a/userdiff.c b/userdiff.c
index 3406adc..ac6d4a1 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -7,7 +7,7 @@ static int ndrivers;
static int drivers_alloc;
#define FUNCNAME(name, pattern) \
- { name, NULL, { pattern, REG_EXTENDED } }
+ { name, NULL, -1, { pattern, REG_EXTENDED } }
static struct userdiff_driver builtin_drivers[] = {
FUNCNAME("html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$"),
FUNCNAME("java",
@@ -23,22 +23,23 @@ FUNCNAME("python", "^[ \t]*((class|def)[ \t].*)$"),
FUNCNAME("ruby", "^[ \t]*((class|module|def)[ \t].*)$"),
FUNCNAME("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$"),
FUNCNAME("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$"),
+{ "default", NULL, -1, { NULL, 0 } },
};
#undef FUNCNAME
static struct userdiff_driver driver_true = {
"diff=true",
NULL,
+ 0,
{ NULL, 0 }
};
-struct userdiff_driver *USERDIFF_ATTR_TRUE = &driver_true;
static struct userdiff_driver driver_false = {
"!diff",
NULL,
+ 1,
{ NULL, 0 }
};
-struct userdiff_driver *USERDIFF_ATTR_FALSE = &driver_false;
static struct userdiff_driver *userdiff_find_by_namelen(const char *k, int len)
{
@@ -80,6 +81,7 @@ static struct userdiff_driver *parse_driver(const char *var,
drv = &drivers[ndrivers++];
memset(drv, 0, sizeof(*drv));
drv->name = xmemdupz(name, namelen);
+ drv->binary = -1;
}
return drv;
}
@@ -100,6 +102,15 @@ static int parse_string(const char **d, const char *k, const char *v)
return 1;
}
+static int parse_tristate(int *b, const char *k, const char *v)
+{
+ if (v && !strcasecmp(v, "auto"))
+ *b = -1;
+ else
+ *b = git_config_bool(k, v);
+ return 1;
+}
+
int userdiff_config_basic(const char *k, const char *v)
{
struct userdiff_driver *drv;
@@ -108,6 +119,8 @@ int userdiff_config_basic(const char *k, const char *v)
return parse_funcname(&drv->funcname, k, v, 0);
if ((drv = parse_driver(k, v, "xfuncname")))
return parse_funcname(&drv->funcname, k, v, REG_EXTENDED);
+ if ((drv = parse_driver(k, v, "binary")))
+ return parse_tristate(&drv->binary, k, v);
return 0;
}
diff --git a/userdiff.h b/userdiff.h
index c64c5f5..1c1eb04 100644
--- a/userdiff.h
+++ b/userdiff.h
@@ -9,12 +9,10 @@ struct userdiff_funcname {
struct userdiff_driver {
const char *name;
const char *external;
+ int binary;
struct userdiff_funcname funcname;
};
-extern struct userdiff_driver *USERDIFF_ATTR_TRUE;
-extern struct userdiff_driver *USERDIFF_ATTR_FALSE;
-
int userdiff_config_basic(const char *k, const char *v);
int userdiff_config_porcelain(const char *k, const char *v);
struct userdiff_driver *userdiff_find_by_name(const char *name);
--
1.6.0.2.639.g4d7f.dirty
^ permalink raw reply related
* [PATCH 2/4] diff: unify external diff and funcname parsing code
From: Jeff King @ 2008-10-05 21:43 UTC (permalink / raw)
To: Matthieu Moy; +Cc: git
In-Reply-To: <20081005214114.GA21875@coredump.intra.peff.net>
Both sets of code assume that one specifies a diff profile
as a gitattribute via the "diff=foo" attribute. They then
pull information about that profile from the config as
diff.foo.*.
The code for each is currently completely separate from the
other, which has several disadvantages:
- there is duplication as we maintain code to create and
search the separate lists of external drivers and
funcname patterns
- it is difficult to add new profile options, since it is
unclear where they should go
- the code is difficult to follow, as we rely on the
"check if this file is binary" code to find the funcname
pattern as a side effect. This is the first step in
refactoring the binary-checking code.
This patch factors out these diff profiles into "userdiff"
drivers. A file with "diff=foo" uses the "foo" driver, which
is specified by a single struct.
Note that one major difference between the two pieces of
code is that the funcname patterns are always loaded,
whereas external drivers are loaded only for the "git diff"
porcelain; the new code takes care to retain that situation.
Signed-off-by: Jeff King <peff@peff.net>
---
This is obviously a large and difficult to read diff. But I hope the
result is a bit more readable.
Makefile | 2 +
diff.c | 241 +++++++-----------------------------------------------------
userdiff.c | 151 +++++++++++++++++++++++++++++++++++++
userdiff.h | 23 ++++++
4 files changed, 203 insertions(+), 214 deletions(-)
create mode 100644 userdiff.c
create mode 100644 userdiff.h
diff --git a/Makefile b/Makefile
index 308dc70..d6f3695 100644
--- a/Makefile
+++ b/Makefile
@@ -389,6 +389,7 @@ LIB_H += transport.h
LIB_H += tree.h
LIB_H += tree-walk.h
LIB_H += unpack-trees.h
+LIB_H += userdiff.h
LIB_H += utf8.h
LIB_H += wt-status.h
@@ -485,6 +486,7 @@ LIB_OBJS += tree-diff.o
LIB_OBJS += tree.o
LIB_OBJS += tree-walk.o
LIB_OBJS += unpack-trees.o
+LIB_OBJS += userdiff.o
LIB_OBJS += usage.o
LIB_OBJS += utf8.o
LIB_OBJS += walker.o
diff --git a/diff.c b/diff.c
index 4e4e439..08f335f 100644
--- a/diff.c
+++ b/diff.c
@@ -11,6 +11,7 @@
#include "attr.h"
#include "run-command.h"
#include "utf8.h"
+#include "userdiff.h"
#ifdef NO_FAST_WORKING_DIRECTORY
#define FAST_WORKING_DIRECTORY 0
@@ -56,80 +57,6 @@ static int parse_diff_color_slot(const char *var, int ofs)
die("bad config variable '%s'", var);
}
-static struct ll_diff_driver {
- const char *name;
- struct ll_diff_driver *next;
- const char *cmd;
-} *user_diff, **user_diff_tail;
-
-/*
- * Currently there is only "diff.<drivername>.command" variable;
- * because there are "diff.color.<slot>" variables, we are parsing
- * this in a bit convoluted way to allow low level diff driver
- * called "color".
- */
-static int parse_lldiff_command(const char *var, const char *ep, const char *value)
-{
- const char *name;
- int namelen;
- struct ll_diff_driver *drv;
-
- name = var + 5;
- namelen = ep - name;
- for (drv = user_diff; drv; drv = drv->next)
- if (!strncmp(drv->name, name, namelen) && !drv->name[namelen])
- break;
- if (!drv) {
- drv = xcalloc(1, sizeof(struct ll_diff_driver));
- drv->name = xmemdupz(name, namelen);
- if (!user_diff_tail)
- user_diff_tail = &user_diff;
- *user_diff_tail = drv;
- user_diff_tail = &(drv->next);
- }
-
- return git_config_string(&(drv->cmd), var, value);
-}
-
-/*
- * 'diff.<what>.funcname' attribute can be specified in the configuration
- * to define a customized regexp to find the beginning of a function to
- * be used for hunk header lines of "diff -p" style output.
- */
-struct funcname_pattern_entry {
- char *name;
- char *pattern;
- int cflags;
-};
-static struct funcname_pattern_list {
- struct funcname_pattern_list *next;
- struct funcname_pattern_entry e;
-} *funcname_pattern_list;
-
-static int parse_funcname_pattern(const char *var, const char *ep, const char *value, int cflags)
-{
- const char *name;
- int namelen;
- struct funcname_pattern_list *pp;
-
- name = var + 5; /* "diff." */
- namelen = ep - name;
-
- for (pp = funcname_pattern_list; pp; pp = pp->next)
- if (!strncmp(pp->e.name, name, namelen) && !pp->e.name[namelen])
- break;
- if (!pp) {
- pp = xcalloc(1, sizeof(*pp));
- pp->e.name = xmemdupz(name, namelen);
- pp->next = funcname_pattern_list;
- funcname_pattern_list = pp;
- }
- free(pp->e.pattern);
- pp->e.pattern = xstrdup(value);
- pp->e.cflags = cflags;
- return 0;
-}
-
/*
* These are to give UI layer defaults.
* The core-level commands such as git-diff-files should
@@ -162,11 +89,11 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
}
if (!strcmp(var, "diff.external"))
return git_config_string(&external_diff_cmd_cfg, var, value);
- if (!prefixcmp(var, "diff.")) {
- const char *ep = strrchr(var, '.');
- if (ep != var + 4 && !strcmp(ep, ".command"))
- return parse_lldiff_command(var, ep, value);
+ switch (userdiff_config_porcelain(var, value)) {
+ case 0: break;
+ case -1: return -1;
+ default: return 0;
}
return git_diff_basic_config(var, value, cb);
@@ -193,21 +120,10 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
return 0;
}
- if (!prefixcmp(var, "diff.")) {
- const char *ep = strrchr(var, '.');
- if (ep != var + 4) {
- if (!strcmp(ep, ".funcname")) {
- if (!value)
- return config_error_nonbool(var);
- return parse_funcname_pattern(var, ep, value,
- 0);
- } else if (!strcmp(ep, ".xfuncname")) {
- if (!value)
- return config_error_nonbool(var);
- return parse_funcname_pattern(var, ep, value,
- REG_EXTENDED);
- }
- }
+ switch (userdiff_config_basic(var, value)) {
+ case 0: break;
+ case -1: return -1;
+ default: return 0;
}
return git_color_default_config(var, value, cb);
@@ -1355,46 +1271,24 @@ static void emit_binary_diff(FILE *file, mmfile_t *one, mmfile_t *two)
emit_binary_diff_body(file, two, one);
}
-static void setup_diff_attr_check(struct git_attr_check *check)
-{
- static struct git_attr *attr_diff;
-
- if (!attr_diff) {
- attr_diff = git_attr("diff", 4);
- }
- check[0].attr = attr_diff;
-}
-
static void diff_filespec_check_attr(struct diff_filespec *one)
{
- struct git_attr_check attr_diff_check;
+ struct userdiff_driver *drv;
int check_from_data = 0;
if (one->checked_attr)
return;
- setup_diff_attr_check(&attr_diff_check);
+ drv = userdiff_find_by_path(one->path);
one->is_binary = 0;
- one->funcname_pattern_ident = NULL;
- if (!git_checkattr(one->path, 1, &attr_diff_check)) {
- const char *value;
-
- /* binaryness */
- value = attr_diff_check.value;
- if (ATTR_TRUE(value))
- ;
- else if (ATTR_FALSE(value))
- one->is_binary = 1;
- else
- check_from_data = 1;
-
- /* funcname pattern ident */
- if (ATTR_TRUE(value) || ATTR_FALSE(value) || ATTR_UNSET(value))
- ;
- else
- one->funcname_pattern_ident = value;
- }
+ /* binaryness */
+ if (drv == USERDIFF_ATTR_TRUE)
+ ;
+ else if (drv == USERDIFF_ATTR_FALSE)
+ one->is_binary = 1;
+ else
+ check_from_data = 1;
if (check_from_data) {
if (!one->data && DIFF_FILE_VALID(one))
@@ -1411,70 +1305,12 @@ int diff_filespec_is_binary(struct diff_filespec *one)
return one->is_binary;
}
-static const struct funcname_pattern_entry *funcname_pattern(const char *ident)
-{
- struct funcname_pattern_list *pp;
-
- for (pp = funcname_pattern_list; pp; pp = pp->next)
- if (!strcmp(ident, pp->e.name))
- return &pp->e;
- return NULL;
-}
-
-static const struct funcname_pattern_entry builtin_funcname_pattern[] = {
- { "bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$",
- REG_EXTENDED },
- { "html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$", REG_EXTENDED },
- { "java",
- "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n"
- "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$",
- REG_EXTENDED },
- { "pascal",
- "^((procedure|function|constructor|destructor|interface|"
- "implementation|initialization|finalization)[ \t]*.*)$"
- "\n"
- "^(.*=[ \t]*(class|record).*)$",
- REG_EXTENDED },
- { "php", "^[\t ]*((function|class).*)", REG_EXTENDED },
- { "python", "^[ \t]*((class|def)[ \t].*)$", REG_EXTENDED },
- { "ruby", "^[ \t]*((class|module|def)[ \t].*)$",
- REG_EXTENDED },
- { "tex",
- "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
- REG_EXTENDED },
-};
-
-static const struct funcname_pattern_entry *diff_funcname_pattern(struct diff_filespec *one)
+static const struct userdiff_funcname *diff_funcname_pattern(struct diff_filespec *one)
{
- const char *ident;
- const struct funcname_pattern_entry *pe;
- int i;
-
- diff_filespec_check_attr(one);
- ident = one->funcname_pattern_ident;
-
- if (!ident)
- /*
- * If the config file has "funcname.default" defined, that
- * regexp is used; otherwise NULL is returned and xemit uses
- * the built-in default.
- */
- return funcname_pattern("default");
-
- /* Look up custom "funcname.$ident" regexp from config. */
- pe = funcname_pattern(ident);
- if (pe)
- return pe;
-
- /*
- * And define built-in fallback patterns here. Note that
- * these can be overridden by the user's config settings.
- */
- for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++)
- if (!strcmp(ident, builtin_funcname_pattern[i].name))
- return &builtin_funcname_pattern[i];
-
- return NULL;
+ struct userdiff_driver *drv = userdiff_find_by_path(one->path);
+ if (!drv)
+ drv = userdiff_find_by_name("default");
+ return drv && drv->funcname.pattern ? &drv->funcname : NULL;
}
void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b)
@@ -1568,7 +1404,7 @@ static void builtin_diff(const char *name_a,
xdemitconf_t xecfg;
xdemitcb_t ecb;
struct emit_callback ecbdata;
- const struct funcname_pattern_entry *pe;
+ const struct userdiff_funcname *pe;
pe = diff_funcname_pattern(one);
if (!pe)
@@ -2108,29 +1944,6 @@ static void run_external_diff(const char *pgm,
}
}
-static const char *external_diff_attr(const char *name)
-{
- struct git_attr_check attr_diff_check;
-
- if (!name)
- return NULL;
-
- setup_diff_attr_check(&attr_diff_check);
- if (!git_checkattr(name, 1, &attr_diff_check)) {
- const char *value = attr_diff_check.value;
- if (!ATTR_TRUE(value) &&
- !ATTR_FALSE(value) &&
- !ATTR_UNSET(value)) {
- struct ll_diff_driver *drv;
-
- for (drv = user_diff; drv; drv = drv->next)
- if (!strcmp(drv->name, value))
- return drv->cmd;
- }
- }
- return NULL;
-}
-
static void run_diff_cmd(const char *pgm,
const char *name,
const char *other,
@@ -2144,9 +1957,9 @@ static void run_diff_cmd(const char *pgm,
if (!DIFF_OPT_TST(o, ALLOW_EXTERNAL))
pgm = NULL;
else {
- const char *cmd = external_diff_attr(attr_path);
- if (cmd)
- pgm = cmd;
+ struct userdiff_driver *drv = userdiff_find_by_path(attr_path);
+ if (drv && drv->external)
+ pgm = drv->external;
}
if (pgm) {
diff --git a/userdiff.c b/userdiff.c
new file mode 100644
index 0000000..3406adc
--- /dev/null
+++ b/userdiff.c
@@ -0,0 +1,151 @@
+#include "userdiff.h"
+#include "cache.h"
+#include "attr.h"
+
+static struct userdiff_driver *drivers;
+static int ndrivers;
+static int drivers_alloc;
+
+#define FUNCNAME(name, pattern) \
+ { name, NULL, { pattern, REG_EXTENDED } }
+static struct userdiff_driver builtin_drivers[] = {
+FUNCNAME("html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$"),
+FUNCNAME("java",
+ "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n"
+ "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$"),
+FUNCNAME("pascal",
+ "^((procedure|function|constructor|destructor|interface|"
+ "implementation|initialization|finalization)[ \t]*.*)$"
+ "\n"
+ "^(.*=[ \t]*(class|record).*)$"),
+FUNCNAME("php", "^[\t ]*((function|class).*)"),
+FUNCNAME("python", "^[ \t]*((class|def)[ \t].*)$"),
+FUNCNAME("ruby", "^[ \t]*((class|module|def)[ \t].*)$"),
+FUNCNAME("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$"),
+FUNCNAME("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$"),
+};
+#undef FUNCNAME
+
+static struct userdiff_driver driver_true = {
+ "diff=true",
+ NULL,
+ { NULL, 0 }
+};
+struct userdiff_driver *USERDIFF_ATTR_TRUE = &driver_true;
+
+static struct userdiff_driver driver_false = {
+ "!diff",
+ NULL,
+ { NULL, 0 }
+};
+struct userdiff_driver *USERDIFF_ATTR_FALSE = &driver_false;
+
+static struct userdiff_driver *userdiff_find_by_namelen(const char *k, int len)
+{
+ int i;
+ for (i = 0; i < ndrivers; i++) {
+ struct userdiff_driver *drv = drivers + i;
+ if (!strncmp(drv->name, k, len) && !drv->name[len])
+ return drv;
+ }
+ for (i = 0; i < ARRAY_SIZE(builtin_drivers); i++) {
+ struct userdiff_driver *drv = builtin_drivers + i;
+ if (!strncmp(drv->name, k, len) && !drv->name[len])
+ return drv;
+ }
+ return NULL;
+}
+
+static struct userdiff_driver *parse_driver(const char *var,
+ const char *value, const char *type)
+{
+ struct userdiff_driver *drv;
+ const char *dot;
+ const char *name;
+ int namelen;
+
+ if (prefixcmp(var, "diff."))
+ return NULL;
+ dot = strrchr(var, '.');
+ if (dot == var + 4)
+ return NULL;
+ if (strcmp(type, dot+1))
+ return NULL;
+
+ name = var + 5;
+ namelen = dot - name;
+ drv = userdiff_find_by_namelen(name, namelen);
+ if (!drv) {
+ ALLOC_GROW(drivers, ndrivers+1, drivers_alloc);
+ drv = &drivers[ndrivers++];
+ memset(drv, 0, sizeof(*drv));
+ drv->name = xmemdupz(name, namelen);
+ }
+ return drv;
+}
+
+static int parse_funcname(struct userdiff_funcname *f, const char *k,
+ const char *v, int cflags)
+{
+ if (git_config_string(&f->pattern, k, v) < 0)
+ return -1;
+ f->cflags = cflags;
+ return 1;
+}
+
+static int parse_string(const char **d, const char *k, const char *v)
+{
+ if (git_config_string(d, k, v) < 0)
+ return -1;
+ return 1;
+}
+
+int userdiff_config_basic(const char *k, const char *v)
+{
+ struct userdiff_driver *drv;
+
+ if ((drv = parse_driver(k, v, "funcname")))
+ return parse_funcname(&drv->funcname, k, v, 0);
+ if ((drv = parse_driver(k, v, "xfuncname")))
+ return parse_funcname(&drv->funcname, k, v, REG_EXTENDED);
+
+ return 0;
+}
+
+int userdiff_config_porcelain(const char *k, const char *v)
+{
+ struct userdiff_driver *drv;
+
+ if ((drv = parse_driver(k, v, "command")))
+ return parse_string(&drv->external, k, v);
+
+ return 0;
+}
+
+struct userdiff_driver *userdiff_find_by_name(const char *name) {
+ int len = strlen(name);
+ return userdiff_find_by_namelen(name, len);
+}
+
+struct userdiff_driver *userdiff_find_by_path(const char *path)
+{
+ static struct git_attr *attr;
+ struct git_attr_check check;
+
+ if (!attr)
+ attr = git_attr("diff", 4);
+ check.attr = attr;
+
+ if (!path)
+ return NULL;
+ if (git_checkattr(path, 1, &check))
+ return NULL;
+
+ if (ATTR_TRUE(check.value))
+ return &driver_true;
+ if (ATTR_FALSE(check.value))
+ return &driver_false;
+ if (ATTR_UNSET(check.value))
+ return NULL;
+ return userdiff_find_by_name(check.value);
+}
diff --git a/userdiff.h b/userdiff.h
new file mode 100644
index 0000000..c64c5f5
--- /dev/null
+++ b/userdiff.h
@@ -0,0 +1,23 @@
+#ifndef USERDIFF_H
+#define USERDIFF_H
+
+struct userdiff_funcname {
+ const char *pattern;
+ int cflags;
+};
+
+struct userdiff_driver {
+ const char *name;
+ const char *external;
+ struct userdiff_funcname funcname;
+};
+
+extern struct userdiff_driver *USERDIFF_ATTR_TRUE;
+extern struct userdiff_driver *USERDIFF_ATTR_FALSE;
+
+int userdiff_config_basic(const char *k, const char *v);
+int userdiff_config_porcelain(const char *k, const char *v);
+struct userdiff_driver *userdiff_find_by_name(const char *name);
+struct userdiff_driver *userdiff_find_by_path(const char *path);
+
+#endif /* USERDIFF */
--
1.6.0.2.639.g4d7f.dirty
^ permalink raw reply related
* [PATCH 1/4] t4012: use test_cmp instead of cmp
From: Jeff King @ 2008-10-05 21:42 UTC (permalink / raw)
To: Matthieu Moy; +Cc: git
In-Reply-To: <20081005214114.GA21875@coredump.intra.peff.net>
This makes erroneous output slightly easier to see. We also
flip the argument order to match our usual style.
Signed-off-by: Jeff King <peff@peff.net>
---
Just a cleanup I noticed while testing.
t/t4012-diff-binary.sh | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh
index b8ec6e9..0f954a3 100755
--- a/t/t4012-diff-binary.sh
+++ b/t/t4012-diff-binary.sh
@@ -25,11 +25,11 @@ cat > expected <<\EOF
EOF
test_expect_success 'diff without --binary' \
'git diff | git apply --stat --summary >current &&
- cmp current expected'
+ test_cmp expected current'
test_expect_success 'diff with --binary' \
'git diff --binary | git apply --stat --summary >current &&
- cmp current expected'
+ test_cmp expected current'
# apply needs to be able to skip the binary material correctly
# in order to report the line number of a corrupt patch.
--
1.6.0.2.639.g4d7f.dirty
^ permalink raw reply related
* [PATCH 0/4] diff text conversion filter
From: Jeff King @ 2008-10-05 21:41 UTC (permalink / raw)
To: Matthieu Moy; +Cc: git
In-Reply-To: <20080930164545.GA20305@sigill.intra.peff.net>
On Tue, Sep 30, 2008 at 12:45:45PM -0400, Jeff King wrote:
> I am about 90% done cleaning it up for preparation (there is a bit of
> refactoring, and I want to make sure I get that just right). I'll post
> it in the next day or so.
Sorry, I didn't get a chance to look at this until today. Patch series
will follow. It is still missing documentation updates and tests, but I
wanted to get you something to look at (and as I am proposing a new
meaning for "diff driver", I would be curious to hear the general
comments).
This is on top of 'next', because it would otherwise conflict with the
funcname pattern changes there.
-Peff
^ permalink raw reply
* Re: [ANNOUNCE] cgit 0.8
From: Asheesh Laroia @ 2008-10-05 20:49 UTC (permalink / raw)
To: Lars Hjemli; +Cc: Git Mailing List
In-Reply-To: <8c5c35580810051310u60859afcvf38845244308cd23@mail.gmail.com>
On Sun, 5 Oct 2008, Lars Hjemli wrote:
> cgit-0.8, another webinterface for git, is now available.
>
> clone: git://hjemli.net/pub/git/cgit
> browse: http://hjemli.net/git/cgit
This is great!
I'm curious - is there any interest in the cgit world in providing gitweb
URL compatibility? That way, migrations from gitweb to cgit would not
break links. I know that's something we've been thinking through at
code.creativecommons.org; gitweb has been a big load on that web server,
but (re-)switching to cgit would mean invalidating people's bookmarked
links again.
Also, Tv or other gitosis maintainers: Is there any interest in supporting
cgit as easily as gitweb is supported in gitosis?
If the answer to both is "We don't personally care about it, but patches
are welcome, " that'll be okay, but obviously I'm hoping for something
else. (-:
Either way, thanks a bundle to all who work on cgit! (And is this the
canonical place to discuss it?)
-- Asheesh.
--
Seleznick's Theory of Holistic Medicine:
Ice Cream cures all ills. Temporarily.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox