Skip to contentSkip to conversation

PATCH: Allow tree-id to return the ID of a tree object

PATCH Philip Pokorny 2 participants 8 messages Jun 15, 2016 Kbuild

lore
Share & tools
lore
#0 lore raw

While playing with cg-ls, I tried:

% cg-ls
... snip ...

100644  blob    bc607fd55f6ce4e56ce87766369b5d4d55ec79af        object.h
100755  blob    f35877a6aa5b68d2fb4a388dcfa9b3e64262604e        parent-id
040000  tree    bfb75011c32589b282dd9c86621dadb0f0bb3866        ppc
100644  blob    d922305ee0f5583bdfcb629f6d4061e11e0fa859        read-cache.c
100644  blob    1ad7ffc555b635fe57fa7834b12d71ff576be065        read-tree.c

... snip ...
% cg-ls bfb75011c32589b282dd9c86621dadb0f0bb3866 <-- the ppc tree ID
Invalid id: bfb75011c32589b282dd9c86621dadb0f0bb3866
usage: cat-file [-t | tagname] <sha1>
usage: cat-file [-t | tagname] <sha1> Invalid id:

Shouldn't cg-ls give a listing of a sub-tree? The cg-help says it takes a TREE-ID?

The problem seems to be that tree-id really only accepts a commit-id and returns the TREE-ID of that commit.

So I modified commit-id, tree-id and parent-id to make them more similar in coding style, force "short-id" names to be at least 4 lower case letters, and have tree-id accept short, unambiguous ID's and bare SHA1-ID's.

Patch attached.

commit-id (mode:100775) renamed from commit-id (mode:100755 sha1:4efcb6bdfdb2b2c5744f5d4d47d92beb7777ed59) +17 -9
Index: commit-id
===================================================================
@@ -9,22 +9,30 @@
 SHA1ONLY="^$SHA1$"
 
 id=$1
+
 if [ ! "$id" ] || [ "$id" = "this" ] || [ "$id" = "HEAD" ]; then
 	id=$(cat .git/HEAD)
-fi
 
-if (echo $id | egrep -vq "$SHA1ONLY") && [ -r ".git/refs/tags/$id" ]; then
+elif [ -r ".git/refs/tags/$id" ]; then
 	id=$(cat ".git/refs/tags/$id")
-fi
 
-if (echo $id | egrep -vq "$SHA1ONLY") && [ -r ".git/refs/heads/$id" ]; then
+elif [ -r ".git/refs/heads/$id" ]; then
 	id=$(cat ".git/refs/heads/$id")
-fi
 
-idpref=$(echo "$id" | cut -c -2)
-idpost=$(echo "$id" | cut -c 3-)
-if [ $(find ".git/objects/$idpref" -name "$idpost*" 2>/dev/null | wc -l) -eq 1 ]; then
-	id=$idpref$(basename $(echo .git/objects/$idpref/$idpost*))
+# Short id's must be lower case and at least 4 digits.
+elif [[ "$id" == [0-9a-z][0-9a-z][0-9a-z][0-9a-z]* ]]; then
+	idpost=${id#??}
+	idpref=${id%$idpost}
+
+	# Assign array elements to matching names
+	idmatch=($(echo .git/objects/$idpref/$idpost*))
+
+	if [ ${#idmatch[*]} -eq 1 ] && [ -r "$idmatch" ]; then
+		id=$idpref${idmatch#.git/objects/$idpref/}
+	elif [ ${#idmatch[*]} -gt 1 ]; then
+		echo "Ambiguous id: $id" >&2
+		exit 1
+	fi
 fi
 
 if echo $id | egrep -vq "$SHA1ONLY"; then
tree-id (mode:100775) renamed from tree-id (mode:100755 sha1:1495ff78af71b57e21653512932bcda88fe05454) +28 -1
Index: tree-id
===================================================================
@@ -7,8 +7,35 @@
 
 SHA1="[A-Za-z0-9]{40}"
 TREE="^tree $SHA1$"
+SHA1ONLY="^$SHA1$"
 
-id=$(cat-file commit $(commit-id "$1") | egrep "$TREE" | cut -d ' ' -f 2)
+id=$1
+
+# Is it a commit?
+commit=$(commit-id $id 2>/dev/null)
+if [ "$commit" ]; then
+	id=$(cat-file commit "$commit") | egrep "$TREE" | cut -d ' ' -f 2)
+
+# Short id's must be lower case and at least 4 digits.
+elif [[ "$id" == [0-9a-z][0-9a-z][0-9a-z][0-9a-z]* ]]; then
+	idpost=${id#??}
+	idpref=${id%$idpost}
+
+	# Assign array elements to matching names
+	idmatch=($(echo .git/objects/$idpref/$idpost*))
+
+	if [ ${#idmatch[*]} -eq 1 ] && [ -r "$idmatch" ]; then
+		id=$idpref${idmatch#.git/objects/$idpref/}
+	elif [ ${#idmatch[*]} -gt 1 ]; then
+		echo "Ambiguous id: $id" >&2
+		exit 1
+	fi
+fi
+
+if echo $id | egrep -vq "$SHA1ONLY"; then
+	echo "Invalid id: $id" >&2
+	exit 1
+fi
 
 if [ "$(cat-file -t "$id")" != "tree" ]; then
 	echo "Invalid id: $id" >&2
parent-id (mode:100775) renamed from parent-id (mode:100755 sha1:f35877a6aa5b68d2fb4a388dcfa9b3e64262604e) +2 -1
Index: parent-id
===================================================================
@@ -5,7 +5,8 @@
 #
 # Takes ID of the current commit, defaults to HEAD.
 
-PARENT="^parent [A-Za-z0-9]{40}$"
+SHA1="[A-Za-z0-9]{40}"
+PARENT="^parent $SHA1$"
 
 id=$(commit-id $1) || exit 1
 
#1 lore raw

Dear diary, on Wed, Apr 27, 2005 at 06:20:55PM CEST, I got a letter where Philip Pokorny <[email protected]> told me that...

Quoted 20 lines

While playing with cg-ls, I tried:

% cg-ls
... snip ...

100644  blob    bc607fd55f6ce4e56ce87766369b5d4d55ec79af        object.h
100755  blob    f35877a6aa5b68d2fb4a388dcfa9b3e64262604e        parent-id
040000  tree    bfb75011c32589b282dd9c86621dadb0f0bb3866        ppc
100644  blob    d922305ee0f5583bdfcb629f6d4061e11e0fa859        read-cache.c
100644  blob    1ad7ffc555b635fe57fa7834b12d71ff576be065        read-tree.c

... snip ...
% cg-ls bfb75011c32589b282dd9c86621dadb0f0bb3866 <-- the ppc tree ID
Invalid id: bfb75011c32589b282dd9c86621dadb0f0bb3866
usage: cat-file [-t | tagname] <sha1>
usage: cat-file [-t | tagname] <sha1> Invalid id:

Shouldn't cg-ls give a listing of a sub-tree? The cg-help says it takes a TREE-ID?

Quoted 8 lines

The problem seems to be that tree-id really only accepts a commit-id and returns the TREE-ID of that commit.

So I modified commit-id, tree-id and parent-id to make them more similar in coding style, force "short-id" names to be at least 4 lower case letters, and have tree-id accept short, unambiguous ID's and bare SHA1-ID's.

Patch attached.

Could you please functionally split and sign off your patch?

Also, I'd prefer not to have the sha1 completion logic duplicated; what about just having commit-id take a parameter not to validate its id? Actually, that's ugly too. I think the cleanest solution would be to reintroduce the cg-Xnormid, now to only really do the _common_ stuff - basically everything up to the typecheck (exclusively) in commit-id.

Signature · 3 lines
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor
#2 lore raw

Re: PATCH[0/4]: Allow tree-id to return the ID of a tree object

Quoted 3 lines · Petr Baudis

Could you please functionally split and sign off your patch?

Apologies, I'm still a bit new to LKML etiquette...

Quoted 7 lines

Also, I'd prefer not to have the sha1 completion logic duplicated; what about just having commit-id take a parameter not to validate its id? Actually, that's ugly too. I think the cleanest solution would be to reintroduce the cg-Xnormid, now to only really do the _common_ stuff - basically everything up to the typecheck (exclusively) in commit-id.

OK, so following this will be a new set of patches (I assume you mean one patch per file changed when you asked for a "functional split") that re-introduce cg-Xnormid, and then convert commit-id, tree-id, and parent-id to use the new core.

In re-writing these, I've put great effort into making the scripts *not* exec a sub-shell or process, so the bash constructs may look strange. I'm sure Linux can exec very quickly, but bash parses and executes even faster when it doesn't have to fork.

#3 lore raw

Re: PATCH[1/4]: Allow tree-id to return the ID of a tree object

In reply to Petr Baudis

Patch to re-introduce cg-Xnormid for common ID normalizing.

cg-Xnormid (mode:100755 sha1:6dc089c8d571f330e2e01d96f79616d6146840ee) renamed from dev/null (tree:6ad600e20c89323c1d3049f75b8ca9b0a2d72167) +47 -0
Index: cg-Xnormid
===================================================================
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+#
+# Normalize an ID to an SHA1 hash value
+#    Strings resolve in order:
+#       NULL, this, HEAD  => .git/HEAD
+#       <tags>
+#       <heads>
+#       short SHA1 (4 or more hex digits)
+#
+# Copyright (c) Philip Pokorny, 2005
+
+id="$1"
+
+if [ ! "$id" ] || [ "$id" = "this" ] || [ "$id" = "HEAD" ]; then
+	read id < .git/HEAD
+
+elif [ -r ".git/refs/tags/$id" ]; then
+	read id < ".git/refs/tags/$id"
+
+elif [ -r ".git/refs/heads/$id" ]; then
+	read id < ".git/refs/heads/$id"
+
+# Short id's must be lower case and at least 4 digits.
+elif [[ "$id" == [0-9a-z][0-9a-z][0-9a-z][0-9a-z]* ]]; then
+	idpost=${id#??}
+	idpref=${id%$idpost}
+
+	# Assign array elements to matching names
+	idmatch=(.git/objects/$idpref/$idpost*)
+
+	if [ ${#idmatch[*]} -eq 1 ] && [ -r "$idmatch" ]; then
+		id=$idpref${idmatch#.git/objects/$idpref/}
+	elif [ ${#idmatch[*]} -gt 1 ]; then
+		echo "Ambiguous id: $id" >&2
+		exit 1
+	fi
+fi
+
+# FIXME? Should we verify the existance of the ID in the object cache?
+
+# If we don't have a 40-char ID by now, it's an error
+if [ ${#id} -ne 40 ]; then
+	echo "Invalid id: $id" >&2
+	exit 1
+fi
+
+echo $id
Makefile (mode:100664) renamed from Makefile (mode:100644 sha1:d73bea1cbb9451a89b03d6066bf2ed7fec32fd31) +1 -1
Index: Makefile
===================================================================
@@ -44,7 +44,7 @@
 	cg-add cg-admin-lsobj cg-cancel cg-clone cg-commit cg-diff \
 	cg-export cg-help cg-init cg-log cg-ls cg-merge cg-mkpatch \
 	cg-patch cg-pull cg-branch-add cg-branch-ls cg-rm cg-seek cg-status \
-	cg-tag cg-update cg-Xlib
+	cg-tag cg-update cg-Xlib cg-Xnormid
 
 COMMON=	read-cache.o
 
#4 lore raw

Re: PATCH[2/4]: Allow tree-id to return the ID of a tree object

In reply to Petr Baudis

Convert commit-id to use the new cg-Xnormid internal script

commit-id (mode:100775) renamed from commit-id (mode:100755 sha1:4efcb6bdfdb2b2c5744f5d4d47d92beb7777ed59) +11 -25
Index: commit-id
===================================================================
@@ -1,39 +1,25 @@
 #!/usr/bin/env bash
 #
 # Get ID of commit associated with given id or HEAD.
+#
 # Copyright (c) Petr Baudis, 2005
 #
-# Takes the appropriate ID, defaults to HEAD.
-
-SHA1="[A-Za-z0-9]{40}"
-SHA1ONLY="^$SHA1$"
-
-id=$1
-if [ ! "$id" ] || [ "$id" = "this" ] || [ "$id" = "HEAD" ]; then
-	id=$(cat .git/HEAD)
-fi
 
-if (echo $id | egrep -vq "$SHA1ONLY") && [ -r ".git/refs/tags/$id" ]; then
-	id=$(cat ".git/refs/tags/$id")
-fi
-
-if (echo $id | egrep -vq "$SHA1ONLY") && [ -r ".git/refs/heads/$id" ]; then
-	id=$(cat ".git/refs/heads/$id")
-fi
+# Save for later error message
+orig="$1"
 
-idpref=$(echo "$id" | cut -c -2)
-idpost=$(echo "$id" | cut -c 3-)
-if [ $(find ".git/objects/$idpref" -name "$idpost*" 2>/dev/null | wc -l) -eq 1 ]; then
-	id=$idpref$(basename $(echo .git/objects/$idpref/$idpost*))
-fi
+# Normalize to SHA1 form
+id=$(cg-Xnormid "$orig")
 
-if echo $id | egrep -vq "$SHA1ONLY"; then
-	echo "Invalid id: $id" >&2
+if [ ! "$id" ]; then
+	# cg-Xnormid already reported the error
 	exit 1
 fi
 
-if [ "$(cat-file -t "$id")" != "commit" ]; then
-	echo "Invalid id: $id" >&2
+# cat-file will verify that $id is a valid SHA1 ID for us
+# If it isn't, we'll get '' back
+if [ "$(cat-file -t "$id" 2>/dev/null)" != "commit" ]; then
+	echo "Invalid commit id: $orig" >&2
 	exit 1
 fi
 
#5 lore raw

Re: PATCH[2/4]: Allow tree-id to return the ID of a tree object

Quoted 3 lines · Philip Pokorny

Convert commit-id to use the new cg-Xnormid internal script

Were these patches accepted?? I ask because while I do seem to see the addition of the new cg-Xnormid, I don't see that tree-id and friends have been updated to use the new file.

But then again, I seem to be having trouble getting my git working directory to track or match the current head. That would be:
49612c471eebd26efe926a71752e254c1cdc382d
right?

Wait... Perhaps I'm seeing cg-Xnormid because it was an "other" file and therefore left in my directory. But that still doesn't explain why my checkedout cache doesn't show the results of the latest changes to cg-help... Even after running 'cg-update origin'

I'm so confused. It seems difficult to know exactly what the state of your cache actually *is* at any given time. Shouldn't cg-status tell you that you have modified, but uncommited files in your cache? Is there any way to know what the tree-id/commit-id your cache is an instance of? Do you have to 'cat .git/blocked' and 'ls -l .git/HEAD' to know?

In clearcase, I could 'ct lsview' and 'ct catcs' to see what my current view/cache was. I can't find the equivalent in cogito...

:v)

#6 lore raw

Re: PATCH[3/4]: Allow tree-id to return the ID of a tree object

In reply to Petr Baudis

Convert tree-id to use cg-Xnormid to normalize an ID

tree-id (mode:100775) renamed from tree-id (mode:100755 sha1:1495ff78af71b57e21653512932bcda88fe05454) +20 -6
Index: tree-id
===================================================================
@@ -1,17 +1,31 @@
 #!/usr/bin/env bash
 #
 # Get ID of tree associated with given commit or HEAD.
+#
 # Copyright (c) Petr Baudis, 2005
 #
-# Takes ID of the appropriate commit, defaults to HEAD.
 
-SHA1="[A-Za-z0-9]{40}"
-TREE="^tree $SHA1$"
+# Save for later error message
+orig="$1"
 
-id=$(cat-file commit $(commit-id "$1") | egrep "$TREE" | cut -d ' ' -f 2)
+# Normalize to SHA1 form
+id=$(cg-Xnormid "$1")
+if [ ! "$id" ]; then
+	# cg-Xnormid already reported the error
+	exit 1
+fi
+
+# Is it a commit?
+idtype=$(cat-file -t $id 2>/dev/null)
+if [ "$idtype" = "commit" ]; then
+	# Get the tree
+	id=$(cat-file commit "$id" | sed -e 's/tree //;q')
+fi
 
-if [ "$(cat-file -t "$id")" != "tree" ]; then
-	echo "Invalid id: $id" >&2
+# cat-file will verify that $id is a valid SHA1 ID for us
+# If it isn't, we'll get '' back
+if [ "$(cat-file -t "$id" 2>/dev/null)" != "tree" ]; then
+	echo "Invalid tree id: $orig" >&2
 	exit 1
 fi
 
#7 lore raw

Re: PATCH[4/4]: Allow tree-id to return the ID of a tree object

In reply to Petr Baudis

Convert parent-id to similar style and function as the new commit-id and tree-id.

NOTE: parent-id uses commit-id rather than cg-Xnormid directly

parent-id (mode:100775) renamed from parent-id (mode:100755 sha1:f35877a6aa5b68d2fb4a388dcfa9b3e64262604e) +11 -4
Index: parent-id
===================================================================
@@ -1,12 +1,19 @@
 #!/usr/bin/env bash
 #
 # Get ID of parent commit to a given revision or HEAD.
+# NOTE: will return multiple SHA1s if ID is a commit with multiple parents
+#
 # Copyright (c) Petr Baudis, 2005
 #
-# Takes ID of the current commit, defaults to HEAD.
 
-PARENT="^parent [A-Za-z0-9]{40}$"
+# Save for later error message
+orig="$1"
 
-id=$(commit-id $1) || exit 1
+# Normalize to SHA1 form and verify its a commit
+id=$(commit-id "$1")
+if [ ! "$id" ]; then
+	# commit-id already reported the error
+	exit 1
+fi
 
-cat-file commit $id | egrep "$PARENT" | cut -d ' ' -f 2
+cat-file commit $id | awk '/^parent/{print $2};/^$/{exit}'