Re: [PATCH] Use perl instead of tac
- From
- Jörg Sommer <joerg@alea.gnuu.de>
- Date
- May 4, 2008, 22:13 UTC
- Message-ID
- <20080504221319.GA14584@alea.gnuu.de>
- In-Reply-To
- <5374CF8E-3E6E-480B-A23B-13BE85C7ABCF@silverinsanity.com>
Hallo Brian,
Brian Gernhardt schrieb am Wed 30. Apr, 11:25 (-0400):
Show 13 quoted lines
> On Apr 30, 2008, at 5:02 AM, Jörg Sommer wrote: > >>> I also dislike the large lists this is carrying around in shell >>> variables. If I'm reading it correctly, the tag list could be >>> replaced >>> by invocations of "git describe --exact-match". >> >> Yes. How to get all tags of a commit? >> >> % git tag foo v1.5.5 >> % git describe --exact-match 9d831805195ba40b62f632acc6bb6e53d3 >> warning: tag 'v1.5.5' is really 'foo' here >> v1.5.5
And how can I get only tags no annotated tags? We can't recreate annotated tags with git rebase.
> Those concerns being: overrunning the length of a shell variable,
Are you shure there is any such bounding? I didn't saw anything about the size of a variables in IEEE 1003.1-2004, but didn't look very carfully. All my shells (bash, dash, zsh) can handle more than 16777217 characters:
dash -c 'a=a; while :; do a=$a$a; echo $a | wc -c; done'
This would be a new version of create_extended_todo_list() without tac. What do you think about it? Is it better readable? But there's a bug.
create_extended_todo_list () {
# The idea of this function is to
# 1. build a list of tags
# 2. go through the list and
# * issue a reset command to the parent of the commit, if the last
# commit was not the parent of the current commit,
# * issue a pick command for simple commits,
# * issue for each merge commit a merge command with the hashs of
# the parent commits,
# * register each parent of a merge and issue a mark command
# (without an ID) after the commit for each registered commit and
# * issue a tag command, if the commit is in the tag list.
# 3. Then go through the created list and
# * add an ID to each mark command and
# * replace all occurences of the hash in reset and merge commands
# by the mark ID
test -e "$DOTEST"/cetl.tmp \
&& die "Someone else uses our filename cetl.tmp." \
"That's not nice"
if test t = "${PRESERVE_TAGS:-}"
then
tag_list=$(git show-ref --abbrev=7 --tags | \
(
while read sha1 tag
do
tag=${tag#refs/tags/}
if test ${last_sha1:-0000} = $sha1
then
saved_tags="$saved_tags:$tag"
else
printf "%s" "${last_sha1:+ $last_sha1#$saved_tags}"
last_sha1=$sha1
saved_tags=$tag
fi
done
echo "${last_sha1:+ $last_sha1:$saved_tags}"
) )
else
tag_list=
fi
mark_these_commits=
while IFS=_ read commit parents subject
do
first_parent=${parents%% *}
if test "${last_commit:-$SHORTUPSTREAM}" != $first_parent
then
test "$first_parent" = $SHORTUPSTREAM &&
first_parent=$SHORTONTO
echo reset $first_parent
fi
unset first_parent
last_commit=$commit case "$parents" in
*' '*)
new_parents=
for p in $parents
do
mark_these_commits=$(insert_value_at_key_into_list \
"$commit" "$p" "$mark_these_commits")
if test "$p" = $SHORTUPSTREAM
then
new_parents="$new_parents $SHORTONTO"
else
new_parents="$new_parents $p"
fi
done
unset p
echo merge $commit ${new_parents# * }
unset new_parents
;;
*)
echo "pick $commit $subject"
;;
esacif tmp=$(get_value_from_list $commit "$tag_list") then for t in $(echo $tmp | tr : ' ') do echo tag $t done fi done > "$DOTEST"/cetl.tmp unset commit parents subject
commit_mark_list=
next_mark=0
last_commit=
while read cmd args
do
case "$cmd" in
pick)
this_commit="${args%% *}"
;;
reset)
this_commit=$args
if tmp=$(get_value_from_list $args "$commit_mark_list")
then
args=":$tmp"
fi
;;
merge)
new_args=
for i in ${args#* }
do
if tmp=$(get_value_from_list $i \
"$commit_mark_list")
then
new_args="$new_args :$tmp"
else
new_args="$new_args $i"
fi
done
this_commit="${args%% *}"
args="$this_commit ${new_args# }"
;;
esac if tmp=$(get_value_from_list "$last_commit" \
"$mark_these_commits") && \
test "${this_commit:-$last_commit}" != $tmp
then
if tmp=$(get_value_from_list "$last_commit" \
"$commit_mark_list")
then
test "$last_cmd" = reset -o "$last_cmd" = tag \
|| echo mark ":$tmp"
else
commit_mark_list=$(insert_value_at_key_into_list \
$next_mark $last_commit "$commit_mark_list")
echo mark ":$next_mark"
next_mark=$(($next_mark + 1))
fi
fi
last_commit=${this_commit:-$last_commit}
unset this_commitecho "$cmd $args" last_cmd=$cmd done < "$DOTEST"/cetl.tmp rm "$DOTEST"/cetl.tmp unset last_cmd last_commit next_mark cmd args tmp commit_mark_list \ mark_these_commits }
The problem is the mark command. If you walk from ONTO to HEAD trough the list, you must know for a commit, if it is used _later_. But don't create a mark if it is used immediately, e.g. pick; merge not pick; mark; merge.
If you walk from HEAD to ONTO, this is much easier. I delayed the mark for the first head of a merge and checked if the next commit is this commit. This way I keep the todo list clean and don't get something like this for --first-parent:
pick abc pick def mark :0 merge 012 foreign-branch
Bye, Jörg.
-- Es ist außerdem ein weit verbreiteter Irrtum das USENET ‚helfen‘ soll. Tatsächlich wurde USENET nachweislich zur persönlichen Belustigung seiner Erfinder geschaffen. Jörg Klemenz <joerg@gmx.net>, <b4ai4o$1u8vmt$2@ID-21915.news.dfncis.de>