Subject: Re: [PATCH v2] contrib git-resurrect: find traces of a branch name and resurrect it

From: Junio C Hamano <[email-masked]>
Date: Mon, 26 Jan 2009 22:31:27 -0800

Thomas Rast <[email-masked]> writes:

> Add a tool 'git-resurrect.sh <branch>' that tries to find traces of
> the <branch> in the HEAD reflog and, optionally, all merge commits in
> the repository.  It can then resurrect the branch, pointing it at the
> most recent of all candidate commits found.
>
> Signed-off-by: Thomas Rast <[email-masked]>
> ---
>
> Fixed the -h to upper-case in the short options summaries, and removed
> a stray 'q' in the default assignment of new_name.

I hate to paint bikeshed, but -H "try-hard" looks somewhat unusual doesn't
it?  It sounds more like --all (find from all possible sources).

> +. git-sh-setup
> +cd_to_toplevel

Why?

> +search_reflog () {
> +        sed -n 's~^\([^ ]*\) .*\tcheckout: moving from '"$1"' .*~\1~p' \
> +                < .git/logs/HEAD
> +}

Once you used ". git-sh-setup", use "$GIT_DIR/logs/HEAD".  That way, you
can work in a bare repository (and you do not have to cd_to_toplevel,
either, I think).

Oh, don't forget to skip this step if the reflog does not exist.

> +search_reflog_merges () {
> +        sed -n 's~^[^ ]* \([^ ]*\) .*\tmerge '"$1"':~\1~p' \
> +                < .git/logs/HEAD
> +}

The two commits both point at the HEAD that merges the other branch into,
so this finds a merge commit that has the tip of target branch as its
second parent.  Is that really what you want?

> +search_merges () {
> +	git rev-list --pretty=tformat:"%h %p:%s" --all |
> +	grep "Merge branch.*'$branch'.*into" |

"git merge tr/topic~4" can say "Merge branch 'tr/topic' (early part)".
Also merge into 'master' won't have "into ...".

> +	while read sha rest; do
> +		parents="$(echo "$rest" | cut -d: -f1)"
> +		case "$parents" in
> +		    *' '*' '*)
> +			warn "$branch took part in octopus merge $sha"
> +			warn "check manually!"
> +			;;
> +		    *' '*)
> +			echo "$parents" | cut -d' ' -f2
> +			;;
> +		esac
> +	done

Reading everything down to the root commit sounds like fun.  rev-list
gives you the output from newer to older so you may want to break out once
you have found enough candidates.

Anyway, if I were doing this script, I'd write this part like this without
a shell loop:

        _x40="[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]"
        _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"

	git rev-list --all --grep="Merge branch '$1'" \
        	--pretty=tformat:"%H %P %s" |
	sed -ne "s/^$_x40 $_x40 \($_x40\) Merge .*/\1/p"