#!/bin/bash
# git-dpm: manage Debian packages in git
#
#  Copyright (C) 2009,2010 Bernhard R. Link
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License version 2 as
#  published by the Free Software Foundation.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc.

# This is assume throughtout the whole file, do not remove!
set -e

# those could cause problems, so remove:
unset CDPATH
unset GREP_COLOR
unset GREP_COLORS
export GREP_OPTIONS=--color=never

lines_must_match=1
VERSION="0.2.1"
GIT="git"
UPSTREAMBRANCH=""
PATCHEDBRANCH=""
DEBIANBRANCH=""
HEADBRANCH=""
ORIGHEADBRANCH=""
DEBUG=false
doforce=false
dosilent=false
allow_nonclean=false
delete_temp_files=true
commit_in_tree=
commitmessage=""
dpatch_forbid_empty=true
# gets -1 if checked and unclean, 1 if checked and clean
checked_if_clean=0
emptytreeexists=false
gitdpm_print_git_commands=false

function debugout() {
	if $DEBUG ; then echo "$@" ; fi
}
function printwarn() {
	echo "git-dpm: WARNING: $*" >&2
}
function printerror() {
	echo "git-dpm: ERROR: $*" >&2
}

while [ $# -gt 0 ] ; do
	case "$1" in
		--help)
			cat <<EOF
git-dpm: manage Debian package in git
Syntax: git-dpm [global options] command [arguments]
Possible commands are:
 init: Create a new project. You need at least an upstream[-*] branch.
 prepare: try to make everything (.orig.tar and branches) ready
           (you might want to call that after a clone or pull).
 status: Check current status.
 checkout-patched: create/update the branch with the patches
 update-patches: export patches to debian/patches/
 import-new-upstream: import-tar + new-upstream
 new-upstream: record changed upstream branch and new tar file
 linearize: 'rebase -i' the patched branch
 tag: add tags for the current version
 cherry-pick: checkout-patched + git's cherry-pick
 import-dsc: import a .dsc file
Low-level-stuff:
 merge-patched-into-debian: usually called by update-patches for you
 rebase-patched: rebase patches to new upstream
 import-tar: import a tar file as git commit
EOF
			exit 0
			;;
		-U)
			shift
			UPSTREAMBRANCH="$1"
			;;
		-P)
			shift
			PATCHEDBRANCH="$1"
			;;
		-D)
			shift
			DEBIANBRANCH="$1"
			;;
		--allow-nonclean)
			# Very bad things can happen with this.
			# todo: decide if better remove it...
			allow_nonclean=true
			;;
		--debug)
			DEBUG=true
			;;
		--debug-git-calls)
			gitdpm_print_git_commands=true
			;;
		--silent)
			dosilent=true
			;;
		--keep-temp)
			delete_temp_files=false
			;;
		--commit-in-tree)
			commit_in_tree=true
			;;
		--no-commit-in-tree)
			commit_in_tree=false
			;;
		--dpatch-allow-empty)
			dpatch_forbid_empty=false
			;;
		--)
			shift
			break
			;;
		-*)
			printerror "Unrecognised option '$1'!"
			exit 1
			;;
		*)
			break
			;;
	esac
	shift
done

export gitdpm_print_git_commands

function gitcmd() {
	if $gitdpm_print_git_commands ; then
		echo "Running $GIT $*" >&2
	fi
	"$GIT" "$@"
}
function xargsgitcmd() {
	if $gitdpm_print_git_commands ; then
		echo "Running $GIT $* ...(xargs input)" >&2
	fi
	xargs --no-run-if-empty "$GIT" "$@"
}

gitdir="$(gitcmd rev-parse --git-dir)"
function checkgitdir() {
	if ! [ -d "$gitdir" ] ; then
		debugout "Could not find $gitdir!"
		printerror "Not in a git repository!"
		return 1
	fi
	if ! mkdir -p "$gitdir/dpm/" ; then
		printerror "Could not create '$gitdir/dpm/'!"
		return 1
	fi
	reldir="$(gitcmd rev-parse --show-cdup || true)"
}
function checkworkingdir() {
	if $(gitcmd rev-parse --is-bare-repository) ; then
		printerror "requested operation does not work in a bare repository!"
		return 1
	fi
	if ! $(gitcmd rev-parse --is-inside-work-tree) ; then
		printerror "requested operation only possible inside working tree!"
		return 1
	fi
}
function cdtoplevel() {
	test -n "$gitdir"
	checkworkingdir
	cd -- "$reldir"
	reldir=""
}
function checkclean() {
	allow_unclean="${1:-ERROR}"
	checked_if_clean=1
	# this is approximately what git-rebase does to check the tree is clean:
	if ! gitcmd update-index --ignore-submodules --refresh > /dev/null; then
		checked_if_clean=-1
		if $allow_unclean ; then
			printwarn "unstaged changes:"
			gitcmd diff-files --name-status -r --ignore-submodules -- >&2
		else
			printerror "cowardly refusing to run because of unstaged changes:"
			gitcmd diff-files --name-status -r --ignore-submodules -- >&2
			return 1
		fi
	fi
	# check that the current index belongs to HEAD or to the empty
	# tree in case HEAD does not work (e.g. directly after git init).
	compareagainst="$(gitcmd rev-parse -q --verify HEAD 2>/dev/null || echo 4b825dc642cb6eb9a060e54bf8d69288fbee4904)"
	diff="$(gitcmd diff-index --cached --name-status -r --ignore-submodules $compareagainst -- | wc -c)"
	if [ "$diff" -ne 0 ] ; then
		checked_if_clean=-1
		if $allow_unclean ; then
			printwarn "uncommited changes:"
			gitcmd diff-index --cached --name-status -r --ignore-submodules $compareagainst -- >&2
		else
			printerror "cowardly refusing to run because of uncommited changes:"
			gitcmd diff-index --cached --name-status -r --ignore-submodules $compareagainst -- >&2
			return 1
		fi
	fi
	return 0
}

# determine which branch we are and what the names of the
# other branches are.
function initbranchvariables() {
	HEADBRANCH="HEAD"
	HEADBRANCH="$(gitcmd symbolic-ref -q "$HEADBRANCH" || echo "DETACHED")"
	HEADBRANCH="${HEADBRANCH#refs/heads/}"

	BASEBRANCH="${1:-HEAD}"
	BASEBRANCH="$(gitcmd symbolic-ref -q "$BASEBRANCH" || echo "${BASEBRANCH}")"
	BASEBRANCH="${BASEBRANCH#refs/heads/}"

	case "$BASEBRANCH" in
		HEAD)
			printerror "You seem to be in an detached HEAD (or something more strange is happening)"
			return 1
			;;
		*/*)
			echo "git-dpm: CONFUSED: Strange rev '$BASEBRANCH' as derived from '${1:-HEAD}'" >&2
			return 1
			;;
	esac
	case "$BASEBRANCH" in
		patched)
			if [ -z "$PATCHEDBRANCH" ] ||
			   [ "x$PATCHEDBRANCH" = "xpatched" ] ; then
				PATCHEDBRANCH="patched"
				if [ -z "$DEBIANBRANCH" ] ; then
					DEBIANBRANCH="master"
				fi
				if [ -z "$UPSTREAMBRANCH" ] ; then
					UPSTREAMBRANCH="upstream"
				fi
			else
				printerror "current branch is called 'patched' but configured patched branch is '$PATCHEDBRANCH'!"
				return 1
			fi
			;;
		patched-*)
			if [ -z "$PATCHEDBRANCH" ] ||
			   [ "x$PATCHEDBRANCH" = "x$BASEBRANCH" ] ; then
				PATCHEDBRANCH="$BASEBRANCH"
				if [ -z "$DEBIANBRANCH" ] ; then
					DEBIANBRANCH="${BASEBRANCH#patched-}"
				fi
				if [ -z "$UPSTREAMBRANCH" ] ; then
					UPSTREAMBRANCH="upstream-${BASEBRANCH#patched-}"
				fi
			else
				printerror "current branch '$BASEBRANCH' looks like a patched branch but configured patched branch is '$PATCHEDBRANCH'!"
				return 1
			fi
			;;
		upstream)
			if [ -z "$UPSTREAMBRANCH" ] ||
			   [ "x$UPSTREAMBRANCH" = "xupstream" ] ; then
				UPSTREAMBRANCH="upstream"
				if [ -z "$DEBIANBRANCH" ] ; then
					DEBIANBRANCH="master"
				fi
				if [ -z "$PATCHEDBRANCH" ] ; then
					PATCHEDBRANCH="patched"
				fi
			else
				printerror "current branch is called 'upstream' but configured upstream branch is '$UPSTREAMBRANCH'!"
				return 1
			fi
			;;
		upstream-*)
			if [ -z "$UPSTREAMBRANCH" ] ||
			   [ "x$UPSTREAMBRANCH" = "x$BASEBRANCH" ] ; then
				UPSTREAMBRANCH="$BASEBRANCH"
				if [ -z "$DEBIANBRANCH" ] ; then
					DEBIANBRANCH="${BASEBRANCH#upstream-}"
				fi
				if [ -z "$PATCHEDBRANCH" ] ; then
					PATCHEDBRANCH="patched-${BASEBRANCH#upstream-}"
				fi
			else
				printerror "current branch '$BASEBRANCH' looks like a upstream branch but configured upstream branch is '$UPSTREAMBRANCH'!"
				return 1
			fi
			;;
		master)
			if [ -z "$UPSTREAMBRANCH" ] ||
			   [ "x$UPSTREAMBRANCH" = "x$BASEBRANCH" ] ; then
				DEBIANBRANCH="$BASEBRANCH"
				if [ -z "$PATCHEDBRANCH" ] ; then
					PATCHEDBRANCH="patched"
				fi
				if [ -z "$UPSTREAMBRANCH" ] ; then
					UPSTREAMBRANCH="upstream"
				fi
			else
				printerror "current branch '$BASEBRANCH' looks like a debian branch but configured upstream branch is '$DEBIANBRANCH'!"
				return 1
			fi
			;;
		*)
			if [ -z "$DEBIANBRANCH" ] ||
			   [ "x$DEBIANBRANCH" = "x$BASEBRANCH" ] ; then
				DEBIANBRANCH="$BASEBRANCH"
				if [ -z "$PATCHEDBRANCH" ] ; then
					PATCHEDBRANCH="patched-$BASEBRANCH"
				fi
				if [ -z "$UPSTREAMBRANCH" ] ; then
					UPSTREAMBRANCH="upstream-$BASEBRANCH"
				fi
			else
				printerror "current branch '$BASEBRANCH' looks like a debian branch but configured debian branch is '$DEBIANBRANCH'!"
				return 1
			fi
			;;
	esac

	debugout "Guessing upstream branch name $UPSTREAMBRANCH"
	debugout "Guessing patched branch name $PATCHEDBRANCH"
	debugout "Guessing debian branch name $DEBIANBRANCH"
	debugout "Guessing current branch to be $HEADBRANCH"

	DEBIANREV="$(gitcmd rev-parse -q --verify "$DEBIANBRANCH" || true)"
	if ${2:-true} && [ -z "$DEBIANREV" ] ; then
		printerror "There seems to be no branch called '$DEBIANBRANCH'"
		return 1
	fi
	UPSTREAMREV="$(gitcmd rev-parse -q --verify "$UPSTREAMBRANCH" || true)"
	PATCHEDREV="$(gitcmd rev-parse -q --verify "$PATCHEDBRANCH" || true)"
	ORIGHEADBRANCH="$HEADBRANCH"
} # initbranchvariables

function isancestor() {
	# todo: investigate if there is an easier way
	# hopefully --max-count has no effect but making it faster...
	test -z "$(gitcmd rev-list --max-count=1 "^$2" "$1")"
}

function parsedpmcontrolfile() {
	control_comment=ERROR
	control_upstream=ERROR
	control_patches=ERROR
	control_patched=ERROR
	control_origtarname=ERROR
	control_origtarsha=ERROR
	control_origtarsize=ERROR
	if test -n "$1" || [ "x$HEADBRANCH" != "x$DEBIANBRANCH" ] ; then
		blob=$(gitcmd rev-parse --verify -q "$DEBIANREV"':debian/.git-dpm' || true)
		if test -z "$blob" ; then
			printerror "No file debian/.git-dpm in branch '$DEBIANBRANCH'!"
			return 1
		fi
		if ! gitcmd cat-file blob "$blob" > "$gitdir/dpm/control" ; then
			if $delete_temp_files ; then
				rm -- "$gitdir/dpm/control"
			fi
			return 1
		fi
		if test "${2:-nothing}" = "keep-control" ; then
			# backup as some commands switch a lot and might want
			# to retain possible options stored in there...
			cp -- "$gitdir/dpm/control" "$gitdir/dpm/oldcontrol"
		fi
		for n in comment patches patched oldupstream upstream origtarname origtarsha origtarsize ; do
			read control_$n
		done < "$gitdir/dpm/control"
		if [ "x$control_origtarsize" = "xERROR" ] ; then
			printerror "malformed debian/.git-dpm in branch '$DEBIANBRANCH'!"
			return 1
		fi
		if test -z "$commit_in_tree" && LC_ALL=C grep -q -s '^commit-in-tree[ 	]*=[ 	]*true[ 	]*\($\|#\)' "$gitdir/dpm/control" ; then
			debugout "enable comit-in-tree as no command line option and set in .git-dpm"
			commit_in_tree=true
		elif test -z "$commit_in_tree" && LC_ALL=C grep -q -s '^no-commit-in-tree[ 	]*=[ 	]*true[ 	]*\($\|#\)' "$gitdir/dpm/control" ; then
			debugout "disabling comit-in-tree as no command line option and disabled in .git-dpm"
			commit_in_tree=false
		fi
		if $delete_temp_files ; then
			rm -- "$gitdir/dpm/control"
		fi
		return 0
	else
		checkworkingdir
		if ! test -f ${reldir}debian/.git-dpm ; then
			printerror "Missing file debian/.git-dpm"
			return 1
		fi
		if test "${2:-}" = "keep-control" ; then
			# backup as some commands switch a lot and might want
			# to retain possible options stored in there...
			cp -- "${reldir}debian/.git-dpm" "$gitdir/dpm/oldcontrol"
		fi
		for n in comment patches patched oldupstream upstream origtarname origtarsha origtarsize ; do
			read control_$n
		done < ${reldir}debian/.git-dpm
		if [ "x$control_origtarsize" = "xERROR" ] ; then
			printerror "malformed debian/.git-dpm!"
			return 1
		fi
		if test -z "$commit_in_tree" && LC_ALL=C grep -q -s '^commit-in-tree[ 	]*=[ 	]*true[ 	]*\($\|#\)' ${reldir}debian/.git-dpm ; then
			debugout "enable comit-in-tree as no command line option and set in .git-dpm"
			commit_in_tree=true
		elif test -z "$commit_in_tree" && LC_ALL=C grep -q -s '^no-commit-in-tree[ 	]*=[ 	]*true[ 	]*\($\|#\)' ${reldir}debian/.git-dpm ; then
			debugout "disabling comit-in-tree as no command line option and disabled in .git-dpm"
			commit_in_tree=false
		fi
		return 0
	fi
}
function checkupstreambranchcurrent() {
	if test -n "$UPSTREAMREV" &&
	   [ "x$UPSTREAMREV" != "x$control_upstream" ] ; then
		printerror "branch '$UPSTREAMBRANCH' changed!"
		echo "If you changed it, try running new-upstream first." >&2
		echo "Or have you forgotten to run prepare after an pull?" >&2
		return 1
	fi
	return 0
}

function checkpatched() {
	badrevs="$(gitcmd rev-list "${UPSTREAMREV:-$control_upstream}..${PATCHEDREV:-$control_patched}" -- ${reldir}debian/)"
	if [ -n "$badrevs" ] ; then
		printerror " patched branch changed debian/ in commits:"
		gitcmd rev-list --pretty=oneline "${UPSTREAMREV:-$control_upstream}..${PATCHEDREV:-$control_patched}" -- ${reldir}debian/ >&2
		return 1
	fi
	return 0
}

# Checking if debian branch contains changes outside debian/
# (except deleting files, which should be permitted)
function checkdebian() {
	relativeto="${1:-${PATCHEDREV:-$control_patched}}"
	# todo: allow filtering files, there might be more than .gitignore...
	# Let's hope ls-tree is always sorted in the filename...
	(cd ${reldir:-.} && gitcmd ls-tree -r "$relativeto") | LC_ALL=C grep -v '	debian/' | LC_ALL=C grep -v '[	/]\.git' > "$gitdir/dpm/tree1"
	(cd ${reldir:-.} && gitcmd ls-tree -r "$DEBIANREV") | LC_ALL=C grep -v '	debian/' | LC_ALL=C grep -v '[	/].git' > "$gitdir/dpm/tree2"
	if (diff --normal "$gitdir/dpm/tree1" "$gitdir/dpm/tree2" || true) | LC_ALL=C grep -q -s '^>' ; then
		printerror "debian branch contains non-debian changes:"
		(diff --normal "$gitdir/dpm/tree1" "$gitdir/dpm/tree2" || true) |
		sed -e 's/^> .*\t/ /p' -e 'd' >&2
		if $delete_temp_files ; then
			rm -- "$gitdir/dpm/tree1" "$gitdir/dpm/tree2"
		fi
		return 1
	fi
	if $delete_temp_files ; then
		rm -- "$gitdir/dpm/tree1" "$gitdir/dpm/tree2"
	fi
	return 0
}

function create_patches() {
	debugout "Create new patches..."
	mkdir -p debian/patches
	touch debian/patches/series
	# --numbered-files? --no-numbered?
	( cd debian/patches ; gitcmd format-patch --no-numbered -k "${UPSTREAMREV:-$control_upstream}".."${PATCHEDREV:-$control_patched}" -- ../..) | sed -e 's#^debian/patches/##' > debian/patches/series
	if [ -s "debian/patches/series" ] ; then
		while read name ; do
			gitcmd add -f "debian/patches/$name"
		done < debian/patches/series
		gitcmd add -f debian/patches/series
	else
		rm debian/patches/series
		gitcmd rm --ignore-unmatch -q debian/patches/series
	fi
	if test -f debian/source/format ; then
		debugout "debian/source/format already exists. Assume it contents are correct"
	else
		debugout "Creating debian/source/format"
		mkdir -p debian/source/
		echo "3.0 (quilt)" > debian/source/format
		gitcmd add -f debian/source/format
	fi
}

function remove_old_patches() {
	debugout "Remove old patches..."
	while read name ; do
		gitcmd rm --ignore-unmatch -q "debian/patches/$name"
	done < debian/patches/series
}

function checkpatchedlinear() {
	gitcmd rev-list --reverse "${UPSTREAMREV:-$control_upstream}".."${PATCHEDREV:-$control_patched}" -- "${reldir}." > "$gitdir/dpm/list"
	parent_expected="${UPSTREAMREV:-$control_upstream}"
	while read rev ; do
		parent="$(gitcmd rev-parse --verify "$rev"^1)"
		if [ x"$parent" != x"$parent_expected" ] ; then
			debugout "'$rev' has parent '$parent' but expected '$parent_expected'"
			if $delete_temp_files ; then
				rm "$gitdir/dpm/list"
			fi
			return 1
		fi
		parent_expected="$rev"
	done < "$gitdir/dpm/list"
	if $delete_temp_files ; then
		rm "$gitdir/dpm/list"
	fi
	return 0
}

##### merge-patched-into-debian ######

function debian_onto_patched() {
	debugout "Create an index with files from '$PATCHEDBRANCH'..."
	gitcmd read-tree "$PATCHEDREV"
	debugout "Remove possible debian/ in patched..."
	gitcmd rm --ignore-unmatch --cached -f -r -- debian
	debugout "To replace it with the one in '$DEBIANBRANCH'..."
	# TODO: what happens if there is no debian/ in debian branch?
	gitcmd read-tree --prefix=debian/ -i "$DEBIANREV:debian"

	debugout "Remove files that were deleted in '$DEBIANBRANCH'..."
	# Find all files removed between upstream and debian:
	(cd ${reldir:-.} && gitcmd ls-tree -r --name-only "${control_oldupstream}") | LC_ALL=C grep -v '	debian/' > "$gitdir/dpm/tree1"
	(cd ${reldir:-.} && gitcmd ls-tree -r --name-only "$DEBIANREV") | LC_ALL=C grep -v '	debian/' > "$gitdir/dpm/tree2"
	(diff --normal "$gitdir/dpm/tree1" "$gitdir/dpm/tree2" || true) |
		sed -e 's/^< //p' -e 'd' |
		xargsgitcmd rm -q --ignore-unmatch --cached --
	if $delete_temp_files ; then
		rm -- "$gitdir/dpm/tree1" "$gitdir/dpm/tree2"
	fi

	# TODO: think about allowing more than .git*
	# (is there anything but .gitignore and .gitattributes one could want?)
	debugout "Restoring possible .git* files from '$DEBIANBRANCH'..."
	(cd ${reldir:-.} && gitcmd ls-tree -r "$DEBIANREV") |
		LC_ALL=C grep -v debian | LC_ALL=C grep '[	/]\.git' | while read mode type object path ; do
			gitcmd update-index --replace --add --cacheinfo "$mode" "$object" "$path"
		done

	debugout "Update working directory to new state..."
	gitcmd checkout-index -f -a
}

# Update the debian branch
# by replacing anything but debian/ with the patched branch
function merge_patched_in_debian() {
	disallow_reverts="$1"
	disallow_nonlinear="$2"
	amendmerge="$3"
	if $disallow_reverts && isancestor "$PATCHEDREV" "$DEBIANREV" ; then
		printerror "cowardly refusing to update patched to already merged version!. Use --allow-revert to override!"
		return 1
	fi
	if ! isancestor "$control_oldupstream" "$DEBIANREV" ; then
		printerror "'$DEBIANBRANCH' does not contain upstream '$control_oldupstream'!"
		return 1
	fi
	if ! isancestor "$control_upstream" "$PATCHEDREV" ; then
		printerror "'$PATCHEDBRANCH' does not contain upstream '$control_upstream'!"
		return 1
	fi
	debugout "Checking if patched branch '$PATCHEDBRANCH' is linear..."
	if ! checkpatchedlinear ; then
		if $disallow_nonlinear ; then
			printerror "'$PATCHEDBRANCH' is not linear!"
			echo "Try git checkout '$PATCHEDBRANCH' && git rebase -i '$UPSTREAMBRANCH' first." >&2
			return 1
		else
			printwarn "'$PATCHEDBRANCH' is not linear!"
		fi
	fi
	debian_onto_patched
	debugout "update debian/.git-dpm for new merged patch state '${PATCHEDREV}'"
	cat > debian/.git-dpm.new <<EOF
# see git-dpm(1) from git-dpm package
${control_patches}
${PATCHEDREV}
${control_upstream}
EOF
	tail -n +5 debian/.git-dpm >> debian/.git-dpm.new
	mv debian/.git-dpm.new debian/.git-dpm
	gitcmd add debian/.git-dpm
	if ${commit_in_tree:-false} ; then
		if gitcmd update-index --add --cacheinfo 160000 "${PATCHEDREV}" debian/.git-dpm-patched && gitcmd checkout debian/.git-dpm-patched ; then
			debugout "changed debian/.git-dpm-patched to ${PATCHEDREV}'"
		else
			printerror "Coult not set debian/.git-dpm-patched to commit ${PATCHEDREV}"
			return 1
		fi
	fi
	debugout "Write the tree, create the commit..."
	tree="$(gitcmd write-tree)"
	if $amendmerge ; then
		rm -f -- "$gitdir"/dpm/msg.author
		gitcmd cat-file commit "$DEBIANREV" | LC_ALL=C awk \
			'BEGIN {auth=ARGV[1];ARGV[1]="";l=0} l {print;next} /^ *$/ {l=1} /^author / {print > auth} {next}' "$gitdir"/dpm/msg.author - > "$gitdir"/dpm/msg.txt
		parents="$(gitcmd rev-list --max-count=1 --parents "$DEBIANREV")"
		parents="${parents#* }"
		parent_arguments=""
		for parent in $parents ; do
			if isancestor "$parent" "$control_patched" ; then
				continue
			fi
			if isancestor "$parent" "$PATCHEDREV" ; then
				continue
			fi
			parent_arguments="$parent_arguments -p $parent"
		done
		commit="$( if test -f "$gitdir"/dpm/msg.author ; then
				author="$(cat "$gitdir"/dpm/msg.author)"
				author="${author#author }"
				GIT_AUTHOR_NAME="${author%%<*}"
				author="${author#*<}"
				GIT_AUTHOR_EMAIL="${author%>*}"
				GIT_AUTHOR_DATE="${author##*>}"
			fi
			export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
			gitcmd commit-tree "$tree" $parent_arguments -p "$PATCHEDREV" \
				< "$gitdir"/dpm/msg.txt  )"
		if $delete_temp_files ; then
			rm -f -- "$gitdir"/dpm/msg.txt "$gitdir"/dpm/msg.author
		fi
	else
		if test -z "$commitmessage" ; then
			commitmessage="merge $PATCHEDBRANCH into $DEBIANBRANCH"
		fi
		commit="$(echo "$commitmessage" | gitcmd commit-tree "$tree" -p "$DEBIANREV" -p "$PATCHEDREV")"
	fi
	debugout "Update '$DEBIANBRANCH'.."
	gitcmd update-ref HEAD "$commit" "$DEBIANREV"
	gitcmd update-index --refresh
	DEBIANREV="$commit"
	control_patched="$PATCHEDREV"
}

function do_merge_patched_into_debian() {
	delete_patched=true
	disallow_reverts=true
	disallow_nonlinear=true
	amendmerge=false
	while [ $# -gt 0 ] ; do
		case "$1" in
			--help)
				cat <<'EOF'
Syntax: git-dpm [global options] merge-patched-into-debian [local options]
 Create a new commit in the debian branch with the debian bits from
 the debian branch and the other bits from the patched branch.
Possible local options:
 --keep-branch: do not remove the patched branch afterwards.
 --amend: replace the last commit from the debian branch instead.
 --allow-revert: allow to rever the patched branch to an older state
 --allow-nonlinear: allow a non-linear patched branch
EOF
				return 0
				;;
			--force)
				doforce=true
				;;
			--keep-branch)
				delete_patched=false
				;;
			--allow-revert)
				disallow_reverts=false
				;;
			--allow-nonlinear)
				disallow_nonlinear=false
				;;
			--amend)
				amendmerge=true
				;;
			--)
				shift
				break
				;;
			-*)
				printerror "git-dpm: Unrecognised update-patches argument '$1'!"
				return 1
				;;
			*)
				break
				;;
		esac
		shift
	done
	if [ $# -gt 0 ] ; then
		printerror "Unexpected arguments '$*'!"
		return 1
	fi
	checkgitdir
	initbranchvariables
	cdtoplevel
	parsedpmcontrolfile ""
	checkclean $allow_nonclean

	if test -z "$PATCHEDREV" ; then
		printerror "merge-patched-into-debian needs a local patched branch, but '$PATCHEDBRANCH' does not exist!"
		return 1
	fi
	checkupstreambranchcurrent

	if [ "x$PATCHEDREV" = "x$control_patched" ]  ; then
		if ! isancestor "$PATCHEDREV" "$DEBIANREV" ; then
			printerror "'$PATCHEDBRANCH' already recorded as merged in debian/.git-dpm, but not ancestor of '$DEBIANBRANCH'!"
			return 1
		fi
		echo "'$PATCHEDBRANCH' already recorded as merged in debian/.git-dpm. Nothing to do..."
		if [ "x$HEADBRANCH" != "x$PATCHEDBRANCH" ] && $delete_patched; then
			gitcmd branch -D "$PATCHEDBRANCH"
			PATCHEDREV=""
		fi
		return 0
	fi
	if [ "x$HEADBRANCH" != "x$DEBIANBRANCH" ] ; then
		gitcmd checkout "$DEBIANBRANCH"
		HEADBRANCH="$DEBIANBRANCH"
	fi
	merge_patched_in_debian "$disallow_reverts" "$disallow_nonlinear" "$amendmerge"
	echo "Updated '$DEBIANBRANCH' with content from '$PATCHEDBRANCH'"
	if $delete_patched ; then
		gitcmd branch -d "$PATCHEDBRANCH"
	fi
	return 0
}

######### update-patches ########

function do_update_patches() {
	allowredo=false
	allowchangesindebian=false
	disallow_reverts=true
	disallow_nonlinear=true
	delete_patched=true
	amendmerge=false
	while [ $# -gt 0 ] ; do
		case "$1" in
			--help)
				cat <<'EOF'
Syntax: git-dpm [global options] update-patches [local options]
 Run merge-patched if necessary and create/update debian/patches directory.

Possible local options:
 --redo: update debian/patches even if no changes are recorded.
 --amend, --keep-branch, --allow-revert, --allow-nonlinear:
  passed to merge-patched
EOF
				return 0
				;;
			--redo)
				allowredo=true
				;;
			# You should not ignore it, so it does not
			# matter the name is too long... ;->
			--ignore-changes-in-debian-branch)
				allowchangesindebian=true
				;;
			--allow-revert)
				disallow_reverts=false
				;;
			--allow-nonlinear)
				disallow_nonlinear=false
				;;
			--keep-branch)
				delete_patched=false
				;;
			--amend)
				amendmerge=true
				;;
			--)
				shift
				break
				;;
			-*)
				printerror "Unrecognised update-patches option '$1'!"
				return 1
				;;
			*)
				break
				;;
		esac
		shift
	done
	if [ $# -gt 0 ] ; then
		printerror "Unexpected arguments '$*'!"
		return 1
	fi
	checkgitdir
	initbranchvariables
	cdtoplevel
	parsedpmcontrolfile ""
	checkclean $allow_nonclean

	if test -z "$PATCHEDREV" ; then
		debugout "No '$PATCHEDBRANCH' branch, only checking recorded stuff!"
		patchedrev="$control_patched"
		if ! gitcmd rev-parse --verify -q "$control_patched" >/dev/null  ; then
			printerror "recorded '$PATCHEDBRANCH' branch '$control_patched' not found in current repository!"
			return 1
		fi
	else
		patchedrev="$PATCHEDREV"
	fi
	if test -z "$UPSTREAMREV" ; then
		debugout "No '$UPSTREAMBRANCH' branch, only checking recorded stuff!"
		upstreamrev="$control_upstream"
	else
		upstreamrev="$UPSTREAMREV"
	fi
	if [ "x$HEADBRANCH" != "x$DEBIANBRANCH" ] ; then
		debugout "Switching to '$DEBIANBRANCH'.."
		gitcmd checkout "$DEBIANBRANCH"
		HEADBRANCH="$DEBIANBRANCH"

	fi
	if ! test -f "debian/.git-dpm" ; then
		printerror "cannot find debian/.git-dpm!"
		echo "Are you in the wrong branch? Or needing init?" >&2
		return 1
	fi

	# TODO: allow mode only looking at recorded branches??
	checkupstreambranchcurrent

	if [ "x$patchedrev" = "x$control_patches" ] &&
	   [ "x$patchedrev" = "x$control_patched" ] &&
	   [ "x$upstreamrev" = "x$control_upstream" ] &&
	   ! $allowredo ; then
		printwarn "doing nothing as branches unchanged. Use --redo to force recreation of patches!"
		if $delete_patched && test -n "$PATCHEDREV"; then
			if [ "x$HEADBRANCH" = "x$PATCHEDBRANCH" ] ; then
				debugout "Not removing '$PATCHEDBRANCH' as currently checked out"
			else
				gitcmd branch -D "$PATCHEDBRANCH"
			fi
		fi
		return 0
	fi

	# check if the invariants still hold:

	debugout "Checking if patched branch contains current upstream branch..."
	if ! isancestor "$upstreamrev" "$patchedrev"; then
		printerror "'$PATCHEDBRANCH' does not contain '$UPSTREAMBRANCH'!"
		return 1
	fi
	debugout "Check if new patched branch contains the old one..."
	if [ x"$control_patches" != x00000000000000000000000000000000 ] && \
	   [ x"$control_patches" != x"NONE" ] && \
	   ! gitcmd rev-parse --verify -q "$control_patches" >/dev/null  ; then
		echo "git-dpm: WARNING/ERROR: current recorded state of patches not found in repository!" >&2
	fi
	amendifneeded=""
	debugout "Checking if patched branch is contained in debian branch..."
	if [ "x$patchedrev" != "x$control_patched" ] ; then
		if test -z "$PATCHEDREV" ; then
			printerror "Confused! How can '$PATCHEDBRANCH' be not up to date if it does not exist?"
			return 1
		fi
		echo "git-dpm: Calling merge-patched-into-debian first..."
		merge_patched_in_debian "$disallow_reverts" "$disallow_nonlinear" "$amendmerge"
		patchedrev="$control_patched"
		if $delete_patched ; then
			gitcmd branch -d "$PATCHEDBRANCH"
		fi
		amendifneeded="--amend"
	elif $amendmerge ; then
		amendifneeded="--amend"
	fi
	update_patches
}
# needs patchedrev (lowercase) and amendifneeded (string) set.
function update_patches() {
	debugout "Check if new patched branch contains no debian/ changes..."
	checkpatched
	# This is not really needed here and only when told to build
	# such a package, but perhaps better test earlier...
	debugout "Check if all changes are in patched..."
	checkdebian || $allowchangesindebian

	if [ -f debian/patches/series ] ; then
		remove_old_patches
	elif [ x"$control_patches" = x"NONE" ] && test -f debian/patches/00list ; then
		remove_old_dpatch
	fi

	mkdir -p debian/patches
	touch debian/patches/series

	create_patches
	cat > debian/.git-dpm.new <<EOF
# see git-dpm(1) from git-dpm package
${patchedrev}
EOF
	tail -n +3 debian/.git-dpm >> debian/.git-dpm.new
	mv debian/.git-dpm.new debian/.git-dpm
	gitcmd add debian/.git-dpm
	echo "Patches updated..."
	gitcmd commit $amendifneeded
	return 0
}

############ prepare ###############

function do_prepare() {
	while [ $# -gt 0 ] ; do
		case "$1" in
			--help)
				cat <<'EOF'
Syntax: git-dpm [global options] prepare
 Make sure everything is ready to build a Debian package or error out.
EOF
				return 0
				;;
			--)
				shift
				break
				;;
			-*)
				printerror "Unrecognised prepare option '$1'!"
				return 1
				;;
			*)
				break
				;;
		esac
		shift
	done
	if [ $# -gt 0 ] ; then
		printerror "Unexpected arguments '$*'!"
		return 1
	fi
	checkgitdir
	initbranchvariables
	cdtoplevel
	parsedpmcontrolfile ""

	if [ x"$control_patches" != x00000000000000000000000000000000 ] && \
	   [ x"$control_patches" != x"NONE" ] && \
	   ! gitcmd rev-parse --verify -q "$control_patches" > /dev/null ; then
		printerror "recorded patched state '$control_patches' does not exist in local repository!"
		return 1
	fi
	if ! gitcmd rev-parse --verify -q "$control_patched" > /dev/null ; then
		printerror "recorded patched state '$control_patched' does not exist in local repository!"
		return 1
	fi
	if ! gitcmd rev-parse --verify -q "$control_upstream" > /dev/null ; then
		printerror "recorded upstream state '$control_upstream' does not exist in local repository!"
		return 1
	fi

	if test -z "$UPSTREAMREV" ; then
		debugout "Creating '$UPSTREAMBRANCH'..."
		gitcmd branch "$UPSTREAMBRANCH" "$control_upstream"
		UPSTREAMREV="$(gitcmd rev-parse --verify "$UPSTREAMBRANCH")"
	elif [ "$UPSTREAMREV" = "$control_upstream" ] ; then
		debugout "'$UPSTREAMBRANCH' matched recorded '$control_upstream'"
	elif isancestor "$UPSTREAMREV" "$control_upstream" ; then
		if [ x"$UPSTREAMBRANCH" = x"$HEADBRANCH" ] ; then
			echo "Updating upstream branch '$UPSTREAMBRANCH' to '$control_upstream'..."
			gitcmd merge "$control_upstream"
		else
			echo "Updating upstream branch '$UPSTREAMBRANCH' to '$control_upstream'..."
			gitcmd update-ref refs/heads/"$UPSTREAMBRANCH" "$control_upstream" "$UPSTREAMREV"
		fi
	elif isancestor "$control_upstream" "$UPSTREAMREV" ; then
		printwarn "'$UPSTREAMBRANCH' has changes not yet recorded! (perhaps you need new-upstream?)"
		return 1
	else
		printerror "'$UPSTREAMBRANCH' is not the expected one!"
		return 1
	fi

	if test -z "$control_origtarname" || test -z "$control_origtarsha" ||
	   test -z "$control_origtarsize" ; then
		echo "git-dpm: CONFUSED: not enough information about tar! (debian/.git-dpm broken?)" >&2
		return 1
	fi

	debugout "Looking for ../$control_origtarname with $control_origtarsha $control_origtarsize"
	if ! [ -e "../$control_origtarname" ] ; then
		if which pristine-tar >/dev/null 2>&1 ; then
			echo "No file '../$control_origtarname', running pristine-tar..."
			pristine-tar checkout "../$control_origtarname"
		else
			if gitcmd branch -a | LC_ALL=C grep pristine-tar > /dev/null ; then
				echo "No file '../$control_origtarname', and no pristine-tar installed..."
			fi
		fi
	fi
	if [ -e "../$control_origtarname" ] ; then
		origsha="$(sha1sum -b -- "../$control_origtarname")"
		origsha="${origsha%% *}"
		origsize="$(stat --printf '%s' ../"$control_origtarname")"
		if [ "x$origsha" != "x$control_origtarsha" ] ||
		   [ "$origsize" -ne "$control_origtarsize" ] ; then
			printerror "file '../$control_origtarname' already exists but has wrong content!"
			echo "expected: $control_origtarsha $control_origtarsize" >&2
			echo "found $origsha $origsize" >&2
			return 1
		fi
		debugout "up to date: ../$control_origtarname"
	else
		echo "Could not find '../$control_origtarname!" >&2
		echo "Without that file dpkg-source will not work!" >&2
		return 1
	fi
	if test -n "$PATCHEDREV" ; then
		if [ "$PATCHEDREV" = "$control_patched" ] ; then
			debugout "'$PATCHEDBRANCH' up to date"
		elif isancestor "$PATCHEDREV" "$DEBIANREV" ; then
			if [ "x$HEADBRANCH" = "x$PATCHEDBRANCH" ] ; then
				printerror "your '$PATCHEDBRANCH' is not up to date!"
				echo "try git reset --hard '$control_patched' or call again from another branch!" >&2
				return 1
			else
				echo "Updating outdated '$PATCHEDBRANCH'..."
				gitcmd update-ref "refs/heads/$PATCHEDBRANCH" "$control_patched" "$PATCHEDREV"
			fi
		elif isancestor "$control_patched" "$PATCHEDREV" ; then
			printwarn "your '$PATCHEDBRANCH' contains yet unrecorded changes"
			return 2
		else
			printwarn "your '$PATCHEDBRANCH' does not match (rebased?)"
			return 3

		fi
	fi
	return 0
}

############### checkout-patched ##############

function reset_patch_branch() {
	if [ "x$HEADBRANCH" = "x$PATCHEDBRANCH" ] ; then
		gitcmd reset --hard "$control_patched"
	else
		gitcmd update-ref "refs/heads/$PATCHEDBRANCH" "$control_patched" "$PATCHEDREV"
		gitcmd checkout "$PATCHEDBRANCH"
		HEADBRANCH="$PATCHEDBRANCH"
	fi
	PATCHEDREV="$control_patched"
}

function do_checkout_patched() {
	use_force=false
	while [ $# -gt 0 ] ; do
		case "$1" in
			--help)
				cat <<'EOF'
Syntax: git-dpm [global options] checkout-patched [local options]
 Create/update the patched branch. The patched branch is temporary and should
 not be pushed anywhere, but is for adding/modifying the patches which will
 be integrated into the history of the debian branch using merge-patched or
 update-patches.
Possible local options:
 --force: reset the branch even if it looks locally modified.
EOF
				return 0
				;;
			--force)
				use_force=true
				;;
			--)
				shift
				break
				;;
			-*)
				printerror "Unrecognised checkout-patched option '$1'!"
				return 1
				;;
			*)
				break
				;;
		esac
		shift
	done
	if [ $# -gt 0 ] ; then
		printerror "Unexpected arguments '$*'!"
		return 1
	fi
	checkgitdir
	initbranchvariables
	cdtoplevel
	parsedpmcontrolfile ""

	if test -n "$PATCHEDREV" ; then
		if [ "$PATCHEDREV" = "$control_patched" ] ; then
			debugout "'$PATCHEDBRANCH' up to date"
			gitcmd checkout "$PATCHEDBRANCH"
			HEADBRANCH="$PATCHEDBRANCH"
		elif isancestor "$PATCHEDREV" "$DEBIANREV" ; then
			echo "Updating outdated '$PATCHEDBRANCH'..."
			reset_patch_branch
		elif isancestor "$control_patched" "$PATCHEDREV" ; then
			if $use_force ; then
				echo "Reverting '$PATCHEDBRANCH'..."
				reset_patch_branch
			else
				printerror "'$PATCHEDBRANCH' is newer than currently recorded version."
				echo "Use --force to change to recorded version!" >&2
				return 1
			fi
		else
			if $use_force ; then
				echo "Reverting/forcibly upgrading '$PATCHEDBRANCH'..."
				reset_patch_branch
			else
				printerror "your '$PATCHEDBRANCH' does not match (rebased?)"
				echo "Use --force to change to recorded version!" >&2
				return 1
			fi

		fi
	else
		gitcmd checkout -b "$PATCHEDBRANCH" "$control_patched"
		PATCHEDREV="$control_patched"
		HEADBRANCH="$PATCHEDBRANCH"
	fi
	return 0
}

############### linearize ##############
function do_linearize() {
	while [ $# -gt 0 ] ; do
		case "$1" in
			--help)
				cat <<'EOF'
Syntax: git-dpm [global options] linearize
 Run git rebase -i on the patched branch.
EOF
				return 0
				;;
			--)
				shift
				break
				;;
			-*)
				printerror "Unrecognised linearize option '$1'!"
				return 1
				;;
			*)
				break
				;;
		esac
		shift
	done
	if [ $# -gt 0 ] ; then
		printerror "Unexpected arguments '$*'!"
		return 1
	fi
	checkgitdir
	initbranchvariables
	cdtoplevel
	parsedpmcontrolfile ""
	checkclean $allow_nonclean
	checkupstreambranchcurrent

	if test -z "$PATCHEDREV" ; then
		debugout "No '$PATCHEDBRANCH', creating it as recorded last '$control_patched'"
		PATCHEDREV="$control_patched"
		gitcmd checkout -b "$PATCHEDBRANCH" "$control_patched"
		HEADBRANCH="$PATCHEDBRANCH"
	fi
	if [ "x$HEADBRANCH" != "x$PATCHEDBRANCH" ] ; then
		debugout "Switching to '$PATCHEDBRANCH'"
		gitcmd checkout "$PATCHEDBRANCH"
		HEADBRANCH="$PATCHEDBRANCH"
	fi
	ret=0
	debugout "Rebase -i checked put '$PATCHEDBRANCH' branch relative to upstream..."
	gitcmd rebase -i "${UPSTREAMREV:-$control_upstream}" || ret=$?
	if [ "$ret" -ne 0 ] ; then
		echo "Once you finished rebase, don't forget to call update-patches"
		return $ret
	elif [ x"$PATCHEDREV" = "x$(gitcmd rev-parse --verify -q HEAD)" ] ; then
		echo "Nothing changed. (Did you change your mind?)"

	else
		echo "Re'base' -i seems to have been successfull. Don't forget to call update-patches!"
		# TODO: perhaps call it here?
		# (but don't forget to update PATCHEDREV first...)
	fi
	return 0
}

############### rebase-patched ##############

function find_likely_upstream() {
	# This is complicated because it needs to be idempotent.
	# i.e. it might have already be run.
	# Another complicating case is backporting debian changes to
	# an older upstream...
	# Things do not get easier as we do not know if merge-patches
	# was calles since the last new upstream version...

	if isancestor "$UPSTREAMREV" "$PATCHEDREV" ; then

		# if it already contains the current branch,
		# the only bad case if things are newer than the current
		# branch and we also contain those...
		if isancestor "$UPSTREAMREV" "$control_upstream" &&
		   isancestor "$control_upstream" "$PATCHEDREV" ; then
		   	debugout "'$PATCHEDBRANCH' contains in '$UPSTREAMBRANCH' but also old upstream containing that one, too..."
		elif isancestor "$UPSTREAMREV" "$control_oldupstream" &&
		     isancestor "$control_oldupstream" "$PATCHEDREV" ; then
		   	debugout "'$PATCHEDBRANCH' contains in '$UPSTREAMBRANCH' but also the old upstream containing that one, too..."
		else
			# That was easy...
			oldupstream="$UPSTREAMREV"
			return 0
		fi
	fi
	if isancestor "$control_upstream" "$PATCHEDREV" ; then
		if isancestor "$control_upstream" "$control_oldupstream" &&
		   isancestor "$control_oldupstream" "$PATCHEDREV" ; then
			:
		fi
		oldupstream="$control_upstream"
		return 0;
	fi
	if isancestor "$control_oldupstream" "$PATCHEDREV" ; then
		oldupstream="$control_oldupstream"
		return 0;
	fi
	printerror "'$PATCHEDBRANCH' seems to be unrelated to current or last recorded '$UPSTREAMBRANCH'."
	echo "Please rebase it yourself to '$UPSTREAMBRANCH' and try again." >&2
	return 1
}
function rebase_patches() {
	if test -z "$PATCHEDREV" ; then
		debugout "No '$PATCHEDBRANCH', creating it as recorded last '$control_patched'"
		PATCHEDREV="$control_patched"
		gitcmd checkout -b "$PATCHEDBRANCH" "$control_patched"
		HEADBRANCH="$PATCHEDBRANCH"
	fi
	if [ "x$HEADBRANCH" != "x$PATCHEDBRANCH" ] ; then
		debugout "Switching to '$PATCHEDBRANCH'"
		gitcmd checkout "$PATCHEDBRANCH"
		HEADBRANCH="$PATCHEDBRANCH"
	fi
	ret=0
	# First determine the upstream $PATCHEDREV is based on
	# and store it as "$oldupstream".
	find_likely_upstream

	echo "Rebasing changes in '$PATCHEDBRANCH' since '$oldupstream' onto '$UPSTREAMBRANCH'..."

	gitcmd rebase -m --onto "$UPSTREAMREV" "$oldupstream" || ret=$?
	if [ "$ret" -ne 0 ] ; then
		echo "Once you finished rebase, don't forget to call update-patches"
		return $ret
	elif [ x"$PATCHEDREV" = "x$(gitcmd rev-parse --verify -q HEAD)" ] ; then
		echo "Nothing changed. (Did something strange happen?)"
		if [ "x$PATCHEDREV" != "x$control_patches" ] ; then
			echo "Don't forget to call update-patches, though."
		fi

	else
		echo "Rebase seems to have been successfull. Don't forget to call update-patches!"
		PATCHEDREV="$(gitcmd rev-parse --verify -q HEAD)"
	fi
	return 0
}

function do_rebase_patched() {
	while [ $# -gt 0 ] ; do
		case "$1" in
			--help)
				cat <<'EOF'
Syntax: git-dpm [global options] rebase-patched
 Rebase the patched branch to a previously recoded new upstream branch.
EOF
				return 0
				;;
			--)
				shift
				break
				;;
			-*)
				printerror "Unrecognised rebase-patched option '$1'!"
				return 1
				;;
			*)
				break
				;;
		esac
		shift
	done
	if [ $# -gt 0 ] ; then
		printerror "Unexpected arguments '$*'!"
		return 1
	fi
	checkgitdir
	initbranchvariables
	cdtoplevel
	parsedpmcontrolfile ""

	if test -z "$UPSTREAMREV" ; then
		debugout "No '$UPSTREAMBRANCH', creating it as recorded last '$control_upstream'"
		UPSTREAMREV="$control_upstream"
		gitcmd update-ref refs/heads/"$UPSTREAMBRANCH" "$control_upstream" "$UPSTREAMREV"
	fi
	rebase_patches
}

################## new-upstream-branch ###############

function record_new_upstream_branch() {
	doamend="${1:-false}"
	doswitchback="${2:-true}"
	if [ "x$control_upstream" = "x$UPSTREAMREV" ] &&
	   [ "x$control_origtarname" = "x$origname" ] &&
	   [ "x$control_origtarsha" = "x$origsha" ] &&
	   [ "x$control_origtarsize" = "x$origsize" ] ; then
		debugout "debian/.git-dpm already up to date!"
		return 0
	fi
	# TODO: support doing this without switching to debian branch?

	OLDHEADBRANCH="$HEADBRANCH"
	if [ "x$DEBIANBRANCH" != "x$HEADBRANCH" ] ; then
		debugout "temporary switching to debian branch '$DEBIANBRANCH'..."
		gitcmd checkout "$DEBIANBRANCH"
		HEADBRANCH="$DEBIANBRANCH"
	fi
	cat > debian/.git-dpm.new <<EOF
# see git-dpm(1) from git-dpm package
${control_patches}
${control_patched}
${control_oldupstream}
${UPSTREAMREV}
${origname}
${origsha}
${origsize}
EOF
	control_upstream="$UPSTREAMREV"
	control_origtarname="$origname"
	control_origtarsha="$origsha"
	control_origtarsize="$origsize"
	tail -n +9 debian/.git-dpm >> debian/.git-dpm.new
	mv debian/.git-dpm.new debian/.git-dpm
	gitcmd add debian/.git-dpm
	if ${commit_in_tree:-false} ; then
		if gitcmd update-index --add --cacheinfo 160000 "${control_upstream}" debian/.git-dpm-upstream && gitcmd checkout debian/.git-dpm-upstream ; then
			debugout "changed debian/.git-dpm-upstream to '${control_upstream}'"
		else
			printerror "Coult not set debian/.git-dpm-upstream to commit '${control_upstream}'"
			return 1
		fi
	fi
	if $doamend ; then
		gitcmd commit --amend
	else
		gitcmd commit -m "record new upstream branch"
	fi
	if $doswitchback && [ "x$DEBIANBRANCH" != "x$OLDHEADBRANCH" ] ; then
		debugout "switching back to original $OLDHEADBRANCH"
		gitcmd checkout "$OLDHEADBRANCH"
		HEADBRANCH="$OLDHEADBRANCH"
	fi
}

function do_new_upstream_branch() {
	dorebase=false
	doamend=false
	disallownochange=true
	while [ $# -gt 0 ] ; do
		case "$1" in
			--help)
				cat <<'EOF'
Syntax: git-dpm [global options] new-upstream [options] <new .orig.tar.* filename> [<new branch to use as upstream branch>]
 Record a new upstream branch and a new tarbal belonging to this.
 It's your responsiblity to have the tarball match the contents of the
 current upstream branch (or the commit given).
 Use import-new-upstream instead if you want to import a tarball as commit first.
Possible local options:
 --new-tarball-only:
   don't refuse to run if the upstream tarball did not change
   (to repair some mistake in choosing that file)
 --amend:
   replace the last commit in the debian branch instead of creating a new one
 --rebase-patched:
   call rebase-patched afterwards to rebase the patches to the upstream
EOF
				return 0
				;;
			--amend)
				doamend=true
				;;
			--new-tarball-only)
				disallownochange=false
				;;
			--rebase|--rebase-patched)
				dorebase=true
				;;
			--)
				shift
				break
				;;
			-*)
				printerror "Unrecognised new-upstream option '$1'!"
				return 1
				;;
			*)
				break
				;;
		esac
		shift
	done
	if [ $# -lt 1 ] ; then
		cat >&2 <<'EOF'
Syntax: git-dpm [global options] new-upstream <new .orig.tar.* filename> [<new branch to use as upstream branch>]
EOF
		return 1
	fi
	origfilename="$1"
	shift
	if ! [ -f "$origfilename" ] ; then
		printerror "no such file: '$origfilename'!"
		return 1
	fi
	origname=${origfilename##*/}
	case "$origname" in
		*.orig.tar.*)
			;;
		*)
			printerror "'$origname' does not contain .orig.tar!"
			return 1
			;;
	esac
	debugout "look at '$origfilename'..."
	origsha="$(sha1sum -b -- "$origfilename")"
	origsha="${origsha%% *}"
	origsize="$(stat --printf '%s' "$origfilename")"

	newupstreambranch=""
	newupstreamrev=""
	if [ $# -gt 0 ] ; then
		newupstreambranch="$1"
		shift
		newupstreamrev="$(gitcmd rev-parse --verify -q "$newupstreambranch" || true)"
		if test -z "$newupstreamrev" ; then
			printerror "git cannot parse '$newupstreambranch':"
			gitcmd rev-parse --verify "$newupstreambranch" || return 1
			# should not be reached:
			return 1
		fi
	fi
	if [ $# -gt 0 ] ; then
		printerror "Unexpected arguments '$*'!"
		return 1
	fi
	checkgitdir
	initbranchvariables
	cdtoplevel
	parsedpmcontrolfile ""

	if test -z "$UPSTREAMREV" ; then
		debugout "setting up '$UPSTREAMBRANCH'..."
		# use newupstreambranch instead of rev so magic can occour...
		# TODO: check if automatic remote detection needs checkout or if update-ref suffices...
		gitcmd update-ref refs/heads/"$UPSTREAMBRANCH" "$newupstreambranch"
		UPSTREAMREV="$newupstreamrev"
	elif test -n "$newupstreamrev" ; then
		if [ "x$newupstreamrev" = "x$UPSTREAMREV" ] ; then
			debugout "'$UPSTREAMBRANCH' is already the same as '$newupstreambranch'"
		elif [ "x$control_upstream" = "x$UPSTREAMREV" ] ; then
			debugout "switching old '$UPSTREAMBRANCH' to new '$newupstreambranch'"
			if [ "x$HEADBRANCH" = "x$UPSTREAMBRANCH" ] ; then
				gitcmd reset --hard "$newupstreamrev"
				UPSTREAMREV="$newupstreamrev"
			else
				gitcmd update-ref refs/heads/"$UPSTREAMBRANCH" "$newupstreambranch" "$UPSTREAMREV"
				UPSTREAMREV="$newupstreamrev"
			fi
		else
			printerror "'$UPSTREAMBRANCH already exists and differs from the recorded one!'"
			return 1
		fi
	fi
	if $disallownochange && [ x"$UPSTREAMREV" = x"$control_upstream" ] ; then
		printerror "cowardly refusing new-upstream-branch if upstream branch has not changed!"
		echo "Have you forgotten to update '$UPSTREAMBRANCH'?" >&2
		echo "Use --new-tarball-only if the tarball has changed but not its contents." >&2
		return 1
	fi
	# TODO: check if branch and contents of .orig.tar match in same
	# way and warn about differences here?
	record_new_upstream_branch "$doamend" true

	if $dorebase ; then
		rebase_patches
	fi
}

####################### tag #########################

function do_tag() {
	dorefresh=false
	dorefreshupstream=false
	disallowstale=true
	donamed=false
	name=""
	while [ $# -gt 0 ] ; do
		case "$1" in
			--help)
				cat <<'EOF'
Syntax: git-dpm [global options] tag [options] [<version>]
 Create tags for the current version.
Local options:
 --refresh: replace tags for this version if they already exist
 --refresh-upstream: dito for the tag of the upstream version
 --named: use the package name in the tags
 --with-name <name>: like --named but explicitly set name
 --allow-stale-patches: don't refuse to run if the patches are not exported
                        (for importing pre-git-dpm packages verbatimly)
EOF
				return 0
				;;
			--refresh)
				dorefresh=true
				;;
			--refresh-upstream)
				dorefreshupstream=true
				;;
			--named)
				donamed=true
				;;
			--with-name)
				donamed=true
				shift
				name="$1"
				;;
			--with-name=*)
				donamed=true
				name="${1#--with-name=}"
				;;
			--allow-stale-patches)
				# makes sense when importing historic packages:
				disallowstale=false
				;;
			--)
				shift
				break
				;;
			-*)
				printerror "Unrecognised tag option '$1'!"
				return 1
				;;
			*)
				break
				;;
		esac
		shift
	done
	version=""
	if [ $# -gt 0 ] ; then
		version="$1"
		shift
	fi
	if [ $# -gt 0 ] ; then
		printerror "Unexpected arguments '$*'!"
		return 1
	fi
	checkgitdir
	initbranchvariables
	parsedpmcontrolfile ""

	# tagging makes no sense if things are not up to date:
	if test -n "$UPSTREAMREV" && [ x"$UPSTREAMREV" != x"$control_upstream" ] ; then
		printerror "'$UPSTREAMBRANCH' differs from recorded one!"
		return 1
	fi
	if test -n "$PATCHEDREV" && [ x"$PATCHEDREV" != x"$control_patched" ] ; then
		printerror "'$PATCHEDREV' differs from recorded one!"
		return 1
	fi
	if $disallowstale && [ x"$control_patches" != x"$control_patched" ] ; then
		printerror "debian/patches not recorded up-to-date!"
		return 1
	fi
	if test -z "$version" ; then
		debugout "Trying to determine debian version..."
		if [ x"$DEBIANBRANCH" = x"$HEADBRANCH" ] ; then
			dpkg-parsechangelog > "$gitdir/dpm/changelog"
		else
			gitcmd cat-file blob "$DEBIANREV:debian/changelog" | dpkg-parsechangelog -l- > "$gitdir/dpm/changelog"
		fi
		if $donamed && test -z "$name" ; then
			name="$(sed -n -e 's/^Source: //p' "$gitdir/dpm/changelog")"
		fi
		version="$(sed -n -e 's/^Version: //p' "$gitdir/dpm/changelog")"
		if $delete_temp_files ; then
			rm "$gitdir/dpm/changelog"
		fi
		debugout "Determined version to be '$version'"
	elif test -z "$name" ; then
		printerror "--named not possible with explicit version, use --with-name name"
		return 1
	fi
	# replace ~ with _, as the formet is not allowed in tags:
	version="${version//\~/_}"
	# split off the epoch, as : is not allowed either...
	if [ x"${version#*:}" != x"$version" ] ; then
		epoch="${version%%:*}"
		version="${version#*:}"
	else
		epoch=""
	fi
	nameprefix="${name}${name:+-}"
function settag() { # name newvalue force
	oldrev=$(gitcmd rev-parse --verify -q "refs/tags/$1" || true)
	if test -z "$oldrev" ; then
		gitcmd tag "$1" "$2"
	elif [ x"$oldrev" = x"$2" ] ; then
		debugout "'$1' already up to date"
	elif ${3:-false} ; then
		gitcmd tag -f "$1" "$2"
	else
		printerror "tag '$1' already exists and differs!"
		return 1
	fi

}
	settag "${nameprefix}upstream$epoch-${version%-*}" "$control_upstream" "$dorefreshupstream"
	settag "${nameprefix}patched$epoch-$version" "$control_patched" "$dorefresh"
	settag "${nameprefix}debian$epoch-$version" "$DEBIANREV" "$dorefresh"
}

############ common stuff ###############

# may be called in a way set -e is not effective...
function getdebianfile () {
	if test -n "$2" ; then
		gitcmd cat-file blob "${2}${1}" || return 1
	elif [ x"$HEADBRANCH" = x"$DEBIANBRANCH" ] && test -e "${reldir}debian/$1" ; then
		cat "${reldir}debian/$1" || return 1
	else
		gitcmd cat-file blob "${DEBIANREV}:debian/$1" || return 1
	fi
}

# may be called in a way set -e is not effective...
function apply_next_patch() {
	patchname="$(sed -e "${next_patch}"'s/\([ #].*\)\?$//p' -n "$gitdir"/dpm/import/series)" || return 1
	if test -z "$patchname" ; then
		return 0
	fi
	patch_date=""
	level="$(sed -e "${next_patch}"'s/^.*[ 	]-p/-p/p' -n "$gitdir"/dpm/import/series)" || return 1
	echo "Applying '$patchname' ${level:+with option '$level' }..."
	cp "$gitdir"/dpm/import/"$patchname" "$gitdir"/dpm/patchfile || return 1
	apply_patch "$1" || return 1
	debugout "patch $patchname applied..."
}

# old_commit_count must be 0 or $gitdir/dpm/oldcommits existing
# may be called in a way set -e is not effective...
function apply_patches() {
	# if != "" the tree object to get the debian stuff from
	debiantreerev="$1"
	# if true, switch to and update PATCHEDBRANCH and PATCHEDREV
	inpatchedbranch="$2"
	rm -rf "$gitdir/dpm/import" || return 1
	mkdir "$gitdir/dpm/import" || return 1
	getdebianfile patches/series "$debiantreerev" >"$gitdir/dpm/import/series" || return 1
	num_patches=0
	num_lines=0
	while read filename option options ; do
		if [ x"$filename" != x"${filename##*/}" ] ; then
			printerror "patch filename contains slash!"
			return 1
		fi
		case "$filename" in
			''|'#'*)
				num_lines="$(( $num_lines + 1))"
				continue
				;;
		esac
		case "$option" in
			''|'#'*|-p*)
				;;
			*)
				printerror "Unsupported option '$option' in debian/patches/series"
				;;
		esac
		case "$options" in
			''|'#'*)
				;;
			*)
				printerror "Unsupported option '$option' in debian/patches/series"
				;;
		esac
		getdebianfile patches/"$filename" "$debiantreerev" >"$gitdir"/dpm/import/"$filename" || return 1
		num_lines="$(( $num_lines + 1))"
		num_patches="$(( $num_patches + 1))"
	done <"$gitdir/dpm/import/series"

	if $inpatchedbranch ; then
		gitcmd checkout "$PATCHEDBRANCH" || return 1
		HEADBRANCH="$PATCHEDBRANCH"
	fi

	if [ $num_patches -eq 0 ] ; then
		debugout "No patches in series, done."
		return 0
	fi
	next_patch=1
	while [ $next_patch -le $num_lines ] ; do
		apply_next_patch "$inpatchedbranch" || return 1
		next_patch="$(( $next_patch + 1))"
	done
	if $delete_temp_files ; then
		rm -r "$gitdir/dpm/import"
	fi

	if $inpatchedbranch ; then
		PATCHEDREV="$(gitcmd rev-parse --verify HEAD)" || return 1
	fi
}

# may be called in a way set -e is not effective...
function apply_next_dpatch_patch() {
	patchname="$(sed -e "${next_patch}"'s/\([ #].*\)\?$//p' -n "$gitdir"/dpm/import/series)" || return 1
	patchname="${patchname%.dpatch}"
	if test -z "$patchname" ; then
		return 0
	fi
	echo "Applying '$patchname'..."
	cp "$gitdir"/dpm/import/"$patchname" "$gitdir"/dpm/patchfile || return 1
	apply_dpatch_patch || return 1
	debugout "patch $patchname applied..."
}

# old_commit_count must be 0 or $gitdir/dpm/oldcommits existing and forcecommitreuse set
# may be called in a way set -e is not effective...
function apply_dpatch_patches() {
	rm -rf "$gitdir/dpm/import" || return 1
	mkdir "$gitdir/dpm/import" || return 1
	getdebianfile patches/00list "" >"$gitdir/dpm/import/series" || return 1
	num_patches=0
	num_lines=0
	while read filename rest ; do
		if [ x"$filename" != x"${filename##*/}" ] ; then
			printerror "patch filename contains slash!"
			return 1
		fi
		case "$filename" in
			''|'#'*)
				num_lines="$(( $num_lines + 1))"
				continue
				;;
		esac
		filename="${filename%.dpatch}"
		if [ "x$rest" != "x" ] ; then
			printerror "Unsupported trailing data '$rest' in debian/patches/00series"
		fi
		getdebianfile patches/"$filename".dpatch "" >"$gitdir"/dpm/import/"$filename" || return 1
		num_lines="$(( $num_lines + 1))"
		num_patches="$(( $num_patches + 1))"
	done <"$gitdir/dpm/import/series"

	gitcmd checkout "$PATCHEDBRANCH" || return 1
	HEADBRANCH="$PATCHEDBRANCH"

	if [ $num_patches -eq 0 ] ; then
		debugout "No patches in 00list, done."
		return 0
	fi
	next_patch=1
	while [ $next_patch -le $num_lines ] ; do
		apply_next_dpatch_patch || return 1
		next_patch="$(( $next_patch + 1))"
	done
	if $delete_temp_files ; then
		rm -r "$gitdir/dpm/import"
	fi

	PATCHEDREV="$(gitcmd rev-parse --verify HEAD)"
}
function remove_old_dpatch() {
	debugout "Remove old dpatch patches..."
	while read filename; do
		if [ x"$filename" != x"${filename##*/}" ] ; then
			printerror "patch filename contains slash!"
			return 1
		fi
		case "$filename" in
			''|'#'*)
				continue
				;;
		esac
		filename="${filename%.dpatch}"
		gitcmd rm --ignore-unmatch -q "debian/patches/${filename}.dpatch"
	done < debian/patches/00list
	gitcmd rm -qf debian/patches/00list
}

############ init ###############

function initial_merging() {
	debugout "Merging the new patched branch into debian/"
	# We are changing the debian branch,
	# so switch there for the case there is an error.
	# Also makes deleting files more easy...
	gitcmd checkout "$DEBIANBRANCH"
	HEADBRANCH="$DEBIANBRANCH"
	# debian_onto_patched uses that variable, so set it...
	control_oldupstream="$UPSTREAMREV"
	debian_onto_patched
	tree=$(gitcmd write-tree)

	commit=$(echo "Merging $PATCHEDBRANCH branch into $DEBIANBRANCH." | gitcmd commit-tree "$tree" -p "$DEBIANREV" -p "$PATCHEDREV")
	gitcmd update-ref -m "Creating $PATCHEDBRANCH branch with the patches applied." refs/heads/"$DEBIANBRANCH" "$commit" "$DEBIANREV"
	DEBIANREV="$commit"
	gitcmd checkout "$DEBIANBRANCH"
	HEADBRANCH="$DEBIANBRANCH"
	doamend="--amend"
	return 0
}

function do_init() {
	patch_author=""
	patch_fallbackauthor=""
	doamend=""
	docommit=true
	patch_edit=false
	allowchangesindebian=false
	createpatches=true
	patchesapplied=false
	while [ $# -gt 0 ] ; do
		case "$1" in
			--help)
				cat <<'EOF'
Syntax: git-dpm [global options] init [options] <.orig.tar.* filename> [<upstream-commit> [<preapplied-commit> [<patched-commit>]]]
 Set up git-dpm for some project.
 You need to have an branch with the upstream sources (Either the contents of
 the .orig.tar file for example as produced by import-tar, or some upstream
 branch with all files outside debian/ and .git* removed that are not in the
 upstream tarball).

 Additionally you can already have a debian branch. If that has a
 debian/patches/series file and neither --patched-applied is given nor
 a <patched-commit> where those are already applied, they will be applied
 on top of <preapplied-commit> (create that commit with any possible not
 debian/patched managed changes, otherwise the <upstream-commit> is used).

 If this commit is called with active branch 'master' or 'upstream',
 the debian branch is assumed to be called 'master' and the
 upstream branch 'upstream'. If it is called 'upstream-'something, or
 something else, then the debian branch is assumed to be called 'something'
 and the upstream branch 'upstream-'something.

 If there is no <upstream-commit> given then the upstream branch is used,
 otherwise that is replaced with the upstream commit.

Possible local options:
 --create-no-patches: don't (re)create debian/patches/
 --patches-applied: patches are already applied in the debian branch
 --no-commit: don't do the final commit but prepare everything for it
EOF
				return 0
				;;
			--create-no-patches)
				createpatches=false
				;;
			--patches-applied)
				patchesapplied=true
				;;
			--no-commit)
				docommit=false
				;;
			--dpatch-allow-empty)
				dpatch_forbid_empty=false
				;;
			--patch-context|-C)
				shift
				lines_must_match="$1"
				;;
			-C*|--patch-context=*)
				lines_must_match="${1#-C}"
				lines_must_match="${lines_must_match#--patch-context=}"
				;;
			--)
				shift
				break
				;;
			-*)
				printerror "Unrecognised init option '$1'!"
				return 1
				;;
			*)
				break
				;;
		esac
		shift
	done
	if [ $# -gt 4 ] ; then
		printerror "Unexpected arguments '$*'!"
		return 1
	fi
	if [ $# -lt 1 ] ; then
		cat >&2 <<'EOF'
Syntax: git-dpm [global options] init [--create-no-patches] [--patches-applies] <.orig.tar.* filename> [<upstream-commit> [<preapplied-commit> [<patched-commit>]]]
EOF
		return 1
	fi
	if ! [ -f "$1" ] ; then
		printerror "no such file: '$1'!"
		return 1
	fi
	origfilename="$1"
	shift
	origname=${origfilename##*/}
	case "$origname" in
		*.orig.tar.*)
			;;
		*)
			printerror "'$origname' does not contain .orig.tar!"
			return 1
			;;
	esac
	NEWUPSTREAMBRANCH=""
	NEWOLDPATCHEDBRANCH=""
	NEWPATCHEDBRANCH=""
	if [ $# -gt 0 ] ; then
		NEWUPSTREAMBRANCH="$1"
		shift
	fi
	if [ $# -gt 0 ] ; then
		NEWOLDPATCHEDBRANCH="$1"
		shift
	fi
	if [ $# -gt 0 ] ; then
		NEWPATCHEDBRANCH="$1"
		shift
	fi
	checkgitdir
	cdtoplevel
	initbranchvariables "" false
	checkclean $allow_nonclean

	if [ x"$HEADBRANCH" = x"$PATCHEDBRANCH" ] ; then
		printerror "git-dpm init cannot be run with '$PATCHEDBRANCH' as active head!"
		return 1
	fi

	debugout "look at '$origfilename'..."
	origsha="$(sha1sum -b -- "$origfilename")"
	origsha="${origsha%% *}"
	origsize="$(stat --printf '%s' "$origfilename")"

	debugout "checking and initializing branches..."
	patchedbranchcreated=false
	debianbranchcreated=false
	if test -n "$DEBIANREV" ; then
		debugout "First test if there already is a debian/.git-dpm in '$DEBIANBRANCH'"
		if gitcmd rev-parse -q --verify "$DEBIANREV"':debian/.git-dpm' ; then
			printerror "debian/.git-dpm already existing in '$DEBIANBRANCH'!"
			return 1
		fi
	elif "$patchesapplied" ; then
		printerror "--patches-applied makes no sense if there is no debian branch ('$DEBIANBRANCH')!"
		return 1
	fi
	if test -n "$NEWUPSTREAMBRANCH" ; then
		NEWUPSTREAMREV="$(gitcmd rev-parse --verify "$NEWUPSTREAMBRANCH")"
	elif test -n "$UPSTREAMREV" ; then
		NEWUPSTREAMREV="$UPSTREAMREV"
	else
		# todo: import the tar-file?
		printerror "No upstream branch argument given and '$UPSTREAMBRANCH' does not yet exists."
		return 1
	fi
	if test -n "$NEWOLDPATCHEDBRANCH" ; then
		NEWOLDPATCHEDREV="$(gitcmd rev-parse --verify "$NEWOLDPATCHEDBRANCH")"
	else
		NEWOLDPATCHEDREV="$NEWUPSTREAMREV"
	fi
	if test -n "$NEWPATCHEDBRANCH" ; then
		NEWPATCHEDREV="$(gitcmd rev-parse --verify "$NEWPATCHEDBRANCH")"
	else
		NEWPATCHEDREV=""
	fi

	if test -z "$UPSTREAMREV" ; then
		debugout "Creating '$UPSTREAMBRANCH'..."
		gitcmd branch "$UPSTREAMBRANCH" "$NEWUPSTREAMREV"
		UPSTREAMREV="$NEWUPSTREAMREV"
	elif [ x"$UPSTREAMREV" = x"$NEWUPSTREAMREV" ] ; then
		debugout "'$UPSTREAMBRANCH' already as it should be..."
	elif [ "x$HEADBRANCH" != "x$UPSTREAMBRANCH" ] ; then
		gitcmd update-ref -m "git-dpm init" refs/heads/"$UPSTREAMBRANCH" "$NEWUPSTREAMREV" "$UPSTREAMREV"
		UPSTREAMREV="$NEWUPSTREAMREV"
	else
		printerror "Upstream branch '$UPSTREAMBRANCH' to be updated but current HEAD!"
		return 1
	fi
	if test -n "$NEWOLDPATCHEDREV" &&
	   ! isancestor "$UPSTREAMREV" "$NEWOLDPATCHEDREV"; then
		printerror "'$NEWOLDPATCHEDBRANCH' does not contain '$UPSTREAMBRANCH'!"
		return 1
	fi
	if test -n "$NEWPATCHEDREV" ; then
		if test -n "$NEWOLDPATCHEDREV" ; then
	   		if ! isancestor "$NEWOLDPATCHEDREV" "$NEWPATCHEDREV"; then
				printerror "'$NEWPATCHEDBRANCH' does not contain '$NEWOLDPATCHEDBRANCH'!"
				return 1
			fi
		elif ! isancestor "$UPSTREAMREV" "$NEWPATCHEDREV"; then
			printerror "'$NEWPATCHEDBRANCH' does not contain '$UPSTREAMBRANCH'!"
			return 1
		fi
	fi
	if test -n "$DEBIANREV" && test -z "$NEWUPSTREAMBRANCH" &&
	   ! isancestor "$UPSTREAMREV" "$DEBIANREV" ; then
		printerror "Your debian branch '$DEBIANBRANCH' does not contain your '$UPSTREAMBRANCH'."
		echo "To use it anyway, specify it as explicit argument.." >&2
		return 1
	fi

	# Find the top-most non-debian branch
	if test -n "$NEWPATCHEDBRANCH" ; then
		topmost="$NEWPATCHEDREV"
		topmostname="$NEWPATCHEDBRANCH"
	elif test -n "$NEWOLDPATCHEDBRANCH" ; then
		topmost="$NEWOLDPATCHEDREV"
		topmostname="$NEWOLDPATCHEDBRANCH"
	else
		topmost="$UPSTREAMREV"
		topmostname="$UPSTREAMBRANCH"
	fi

	if [ x"$UPSTREAMREV" != x"$topmost" ] ; then
		debugout "Check if '$UPSTREAMBRANCH'..'$topmostname' contains any debian/ changes"
		badrevs="$(gitcmd rev-list "$UPSTREAMREV..$topmost" -- ${reldir}debian/ | wc -l)"
		if [ 0 -lt "$badrevs" ] ; then
			printerror "'$topmostname' contains commits changing debian/:"
			gitcmd rev-list --pretty=oneline "$UPSTREAMREV..$topmost" -- ${reldir}debian/ >&2
			return 1
		fi
	fi

	if test -z "$DEBIANREV" ; then
		if gitcmd rev-parse --verify -q "$topmost:debian" > /dev/null ; then
			printerror "Cowardly refusing to run with no debian branch '$DEBIANBRANCH' but a debian/ in '$topmostname'!"
			cat >&2 <<EOF
While having a debian/ directory in your upstream sources is no problem,
having one when not yet having a debian branch could mean you have
misunderstood something. To not be pestered just create that branch.
EOF
			return 1
		fi
	fi

	if test -n "$DEBIANREV" && ! "$patchesapplied" ; then
		debugout "Check if '$DEBIANBRANCH' does not contain any unexpected changes relative to '${NEWOLDPATCHEDBRANCH:-$UPSTREAMBRANCH}'..."
		if ! checkdebian "${NEWOLDPATCHEDREV:-$UPSTREAMREV}" ; then
			printerror "Your debian branch '$DEBIANBRANCH' contains non-debian changes relative to '${NEWOLDPATCHEDBRANCH:-$UPSTREAMBRANCH}'!"
			echo "If your debian branch already has the patches applied, use --patches-applied." >&2
			if test -n "$NEWOLDPATCHEDREV" ; then
				cat >&2 <<EOF
If there are differences to the upstream code not under patch management,
apply them to some new branch (or detached head) on top of '$UPSTREAMBRANCH',
and specify that as "preapplied" (third argument to init).
EOF
			fi
			return 1
		fi
	fi

	if test -z "$DEBIANREV" ; then
		# if there is no debian branch, there can be no patches in it...
		PATCHEDREVnew="${NEWPATCHEDREV:-${NEWOLDPATCHEDREV:-$UPSTREAMREV}}"
		if [ x"$PATCHEDREV" = x"$PATCHEDREVnew" ] ; then
			debugout "'$PATCHEDBRANCH' already up to date..."
		elif [ -z "$PATCHEDREV" ] ; then
			debugout "Setting '$PATCHEDBRANCH' branch"
			gitcmd update-ref -m "git-dpm init" refs/heads/"$PATCHEDBRANCH" "$PATCHEDREVnew"
			PATCHEDREV="$PATCHEDREVnew"
		else
			echo "Overwriting '$PATCHEDBRANCH' (was '$PATCHEDREV')..."
			gitcmd update-ref -m "git-dpm init" refs/heads/"$PATCHEDBRANCH" "$PATCHEDREVnew" "$PATCHEDREV"
			PATCHEDREV="$PATCHEDREVnew"
		fi
		gitcmd checkout -b "$DEBIANBRANCH" "$PATCHEDREV"
		DEBIANREV="$PATCHEDREV"
		HEADBRANCH="$DEBIANBRANCH"
	else
		debugout "Create '$PATCHEDBRANCH'..."
		if test -n "$NEWPATCHEDBRANCH" ; then
			if [ x"$PATCHEDREV" != x"$NEWPATCHEDREV" ] ; then
				if [ x"$HEADBRANCH" = x"$PATCHEDBRANCH" ] ; then
					printerror "Cannot change '$PATCHEDBRANCH' when it's checked out!"
					return 1
				fi
				debugout "Changing to given '$NEWPATCHEDREV'..."
				gitcmd update-ref -m "git-dpm init" refs/heads/"$PATCHEDBRANCH" "$NEWPATCHEDREV" "$PATCHEDREV"
				PATCHEDREV="$NEWPATCHEDREV"
			else
				debugout "Already up to date..."
			fi
		elif gitcmd rev-parse -q --verify "$DEBIANREV:debian/patches/series" >/dev/null ; then
			debugout "found debian/patches/series, trying to apply quilt series..."
			patched_base="${NEWOLDPATCHEDREV:-$UPSTREAMREV}"
			if [ x"$PATCHEDREV" != x"$patched_base" ] ; then
				if [ x"$HEADBRANCH" = x"$PATCHEDBRANCH" ] ; then
					printerror "Cannot change '$PATCHEDBRANCH' when it's checked out!"
					return 1
				fi
				debugout "Starting at '${NEWPATCHEDBRANCH:-$UPSTREAMBRANCH}'..."
				gitcmd update-ref -m "git-dpm init" refs/heads/"$PATCHEDBRANCH" "$patched_base" "$PATCHEDREV"
				PATCHEDREV="$patched_base"
			fi
			old_commit_count=0
			apply_patches "" true
		elif gitcmd rev-parse -q --verify "$DEBIANREV:debian/patches/00list" >/dev/null ; then
			debugout "found debian/patches/00list, trying to apply dpatch series..."
			patched_base="${NEWOLDPATCHEDREV:-$UPSTREAMREV}"
			if [ x"$PATCHEDREV" != x"$patched_base" ] ; then
				if [ x"$HEADBRANCH" = x"$PATCHEDBRANCH" ] ; then
					printerror "Cannot change '$PATCHEDBRANCH' when it's checked out!"
					return 1
				fi
				debugout "Starting at '${NEWPATCHEDBRANCH:-$UPSTREAMBRANCH}'..."
				gitcmd update-ref -m "git-dpm init" refs/heads/"$PATCHEDBRANCH" "$patched_base" "$PATCHEDREV"
				PATCHEDREV="$patched_base"
			fi
			old_commit_count=0
			apply_dpatch_patches
		else
			debugout "No debian/patches..."
			patched_base="${NEWOLDPATCHEDREV:-$UPSTREAMREV}"
			if [ x"$PATCHEDREV" != x"$patched_base" ] ; then
				if [ x"$HEADBRANCH" = x"$PATCHEDBRANCH" ] ; then
					printerror "Cannot change '$PATCHEDBRANCH' when it's checked out!"
					return 1
				fi
				debugout "Changing to given '${NEWPATCHEDBRANCH:-$UPSTREAMBRANCH}'..."
				gitcmd update-ref -m "git-dpm init" refs/heads/"$PATCHEDBRANCH" "$patched_base" "$PATCHEDREV"
				PATCHEDREV="$patched_base"
			else
				debugout "Already up to date..."
			fi
		fi
		if "$patchesapplied" ; then
			debugout "Make sure debian branch does not contain any additional changes..."
			if ! checkdebian "$PATCHEDREV" ; then
				printerror "Your debian branch '$DEBIANBRANCH' contains non-debian changes!"
				if test -z "$NEWPATCHEDREV" ; then
					cat >&2 <<EOF
Try to make those changes to the patched branch '$PATCHEDBRANCH', too,
and try again with that given as "patched-commit" (forth argument to init).
EOF
				fi
				if [ x"$HEADBRANCH" != "x$PATCHEDBRANCH" ] ; then
					gitcmd checkout "$PATCHEDBRANCH"
					HEADBRANCH="$PATCHEDBRANCH"
				fi
				return 1
			fi
		fi
		if [ x"$DEBIANREV" = x"$PATCHEDREV" ] ; then
			debugout "'$DEBIANBRANCH' already contains what is needed..."
		else
			initial_merging
		fi
	fi
	if [ x"$HEADBRANCH" != "x$DEBIANBRANCH" ] ; then
		gitcmd checkout "$DEBIANBRANCH"
		HEADBRANCH="$DEBIANBRANCH"
	fi

	if $createpatches ; then
		mkdir -p debian/patches
		if [ -f debian/patches/series ] ; then
			remove_old_patches
		elif [ -f debian/patches/00list ] ; then
			remove_old_dpatch
		fi
		create_patches
		control_patches="${PATCHEDREV}"
	else
		control_patches="${UPSTREAMREV}"
	fi
	cat > debian/.git-dpm <<EOF
# see git-dpm(1) from git-dpm package
${control_patches}
${PATCHEDREV}
${UPSTREAMREV}
${UPSTREAMREV}
${origname}
${origsha}
${origsize}
EOF
	if ${commit_in_tree:-false} ; then
		echo "commit-in-tree=true" >> debian/.git-dpm
	fi
	gitcmd add -f debian/.git-dpm
	if ${commit_in_tree:-false} ; then
		if gitcmd update-index --add --cacheinfo 160000 "${UPSTREAMREV}" debian/.git-dpm-upstream && gitcmd checkout debian/.git-dpm-upstream ; then
			debugout "changed debian/.git-dpm-upstream to '${UPSTREAMREV}'"
		else
			printerror "Coult not set debian/.git-dpm-upstream to commit '${UPSTREAMREV}'"
			return 1
		fi
		if gitcmd update-index --add --cacheinfo 160000 "${PATCHEDREV}" debian/.git-dpm-patched && gitcmd checkout debian/.git-dpm-patched ; then
			debugout "changed debian/.git-dpm-patched to ${PATCHEDREV}'"
		else
			printerror "Coult not set debian/.git-dpm-patched to commit ${PATCHEDREV}"
			return 1
		fi
	fi
	if test -n "$PATCHEDREV" ; then
		debugout "remove '$PATCHEDBRANCH', so it does not get stale"
		gitcmd branch -d "$PATCHEDBRANCH"
		PATCHEDREV=""
	fi
	if $docommit ; then
		gitcmd commit $doamend -m "Initialize git-dpm"
	else
		echo "debian/.git-dpm created, don't forget to commit $doamend!"
	fi
	return 0
}

########### status ##############

function check_origname() {
	gitcmd cat-file blob "$DEBIANREV:debian/changelog" | dpkg-parsechangelog -l- > "$gitdir/dpm/changelog"
	version="$(sed -n -e 's/^Version: //p' "$gitdir/dpm/changelog")"
	sourcename="$(sed -n -e 's/^Source: //p' "$gitdir/dpm/changelog")"
	if $delete_temp_files ; then
		rm "$gitdir/dpm/changelog"
	fi
	version="${version#*:}"
	upstreamversion="${version%-*}"
	if [ x"${sourcename}_${upstreamversion}" = x"${control_origtarname%.orig.tar*}" ] ; then
		debugout "name of '$control_origtarname' matches what debian/changelog says"
	else
		printwarn "guessing from your debian/changelog, your upstream file should be named '${sourcename}_${upstreamversion}.orig.tar.*' but it is named '${control_origtarname}'"
		return 1
	fi
}

function do_status() {
	status_ret=0
	while [ $# -gt 0 ] ; do
		case "$1" in
			--help)
				cat <<'EOF'
Syntax: git-dpm [global options] status [branch]
 Check the current status.
EOF
				return 0
				;;
			--)
				shift
				break
				;;
			-*)
				printerror "Unrecognised status option '$1'!"
				return 1
				;;
			*)
				break
				;;
		esac
		shift
	done
	if [ $# -gt 1 ] ; then
		printerror "Unexpected arguments '$*'!"
		return 1
	fi
	checkgitdir
	checkclean true
	if [ "$checked_if_clean" -lt 1 ] ; then
		status_ret=3
	fi
	initbranchvariables "${1:-HEAD}"
	if test -z "$UPSTREAMREV" ; then
		echo "No branch named '$UPSTREAMBRANCH'."
		status_ret=2
	else
		debugout "Upstream branch '$UPSTREAMBRANCH': ${UPSTREAMREV}"
	fi
	if test -z "$PATCHEDREV" ; then
		debugout "'$PATCHEDBRANCH' does currently not exist."
	else
		debugout "Upstream branch '$PATCHEDBRANCH': ${PATCHEDREV}"
		echo "'$PATCHEDBRANCH' exists."
	       	echo "Once you are finished doing changes to this, don't forget to run update-patches (or at least merge-patched-into-debian)"
	       	echo "(Or remove it if it is a left-over from an old patch editing session)"
	fi
	if test -z "$DEBIANREV" ; then
		echo "No branch named '$DEBIANBRANCH'."
		status_ret=2
	else
		debugout "Upstream branch '$DEBIANBRANCH': ${DEBIANREV}"
	fi
	debugout "Checking if branches are up to date..."
	cancheckdebian=false
	if [ -n "$UPSTREAMREV" ] && [ -n "$PATCHEDREV" ] ; then
		if ! isancestor "$UPSTREAMREV" "$PATCHEDREV"; then
			echo "NOT UP TO DATE: '$PATCHEDBRANCH' does not contain '$UPSTREAMBRANCH'!" >&2
			status_ret=3
		fi
	else
		debugout "Could not check if '$PATCHEDBRANCH' contains '$UPSTREAMBRANCH'"
	fi
	if [ -z "$PATCHEDREV" ] && [ -n "$UPSTREAMREV" ] && [ -n "$DEBIANREV" ] ; then
		if ! isancestor "$UPSTREAMREV" "$DEBIANREV"; then
			echo "NOT UP TO DATE: '$DEBIANBRANCH' does not contain '$UPSTREAMBRANCH'!" >&2
			status_ret=3
		fi
	fi
	debugout "Checking if patched branch changed debian/ ..."
	if [ -n "$UPSTREAMREV" -a -n "$PATCHEDREV" ] ; then
		checkpatched || status_ret=4
	fi
	debugout "Check contents of debian/.git-dpm file..."
	if parsedpmcontrolfile "${1:-}" ; then
		if [ x"$control_patches" != x00000000000000000000000000000000 ] && \
		   [ x"$control_patches" != x"NONE" ] && \
		   ! gitcmd rev-parse --verify -q "$control_patches" >/dev/null  ; then
			printerror \
"revision '$control_patches' recorded in debian/.git-dpm to be the current state of debian/patches not found in repository!"
			status_ret=4
		elif ! gitcmd rev-parse --verify -q "$control_patched" >/dev/null  ; then
			printerror \
"patched revision '$control_patched' from debian/.git-dpm not found in repository!"
			status_ret=4
		else
			if [ "x$control_patches" = "x$control_patched" ] ; then
				debugout \
"Current recorded state of debian/patches matched recorded patch branch."
			else
				echo \
"NOT UP TO DATE: debian/patches (update-patches needed?)" >&2
				status_ret=3
			fi
			if test -n "$PATCHEDREV" ; then
				if [ "x$PATCHEDREV" = "x$control_patched" ] ; then
					debugout \
"up to date: '$PATCHEDBRANCH' is the same as recorded in debian/.git-dpm."
					cancheckdebian=true
				elif isancestor "$control_patched" "$PATCHEDREV" ; then
					echo \
"NOT UP TO DATE: '$PATCHEDBRANCH' is newer than listed in debian/.git-dpm"
					echo \
"(try running merge-patched-into-debian or update-patches)"
					status_ret=3
				elif isancestor "$PATCHEDREV" "$control_patched" ; then
					printwarn \
"'$PATCHEDBRANCH' looks outdated!"
					status_ret=3
				elif test -n "$DEBIANREV" && isancestor "$DEBIANREV" "$PATCHEDREV" ; then
					printwarn \
"'$PATCHEDBRANCH' looks outdated!"
					status_ret=3
				else
					echo \
"NOT UP TO DATE: '$PATCHEDBRANCH' differs from recorded one (rebased?)"
					status_ret=3
				fi
			# with no patched branch, less things to check...
			elif ! isancestor "$control_patched" "$DEBIANREV" ; then
				printerror "previously recorded revision '$control_patched' not contained in current debian branch!"
				status_ret=4
			else
				cancheckdebian=true
			fi
		fi
		if ! gitcmd rev-parse --verify -q "$control_upstream" >/dev/null ; then
			printerror "upstream revision '$control_upstream' from debian/.git-dpm not found in repository!"
			status_ret=4
		elif test -n "$UPSTREAMREV" ; then
			if [ "x$UPSTREAMREV" = "x$control_upstream" ] ; then
				debugout "up to date: 'upstream' is the same as recorded in debian/.git-dpm."
			elif ! isancestor "$control_upstream" "$UPSTREAMREV" ; then
				printerror "'$UPSTREAMBRANCH' does not contain previously recorded revision '$control_upstream'!"
				status_ret=4
			else
				echo "NOT UP TO DATE: 'upstream' is newer than listed in debian/.git-dpm"
				status_ret=3
			fi
		# with no upstream branch, less things to check...
		elif test -n "$PATCHEDREV" ; then
			if ! isancestor "$control_upstream" "$PATCHEDREV" ; then
				printerror "previously recorded upstream revision '$control_upstream' not contained in current patched branch!"
				status_ret=4
			fi
		elif ! isancestor "$control_upstream" "$DEBIANREV" ; then
			printerror "previously recorded upstream revision '$control_upstream' not contained in current debian branch!"
			status_ret=4
		fi
		if [ -e "../$control_origtarname" ] ; then
			debugout "../$control_origtarname is there, to check it contents run prepare"
			if ! check_origname ; then
				status_ret=4
			fi
		else
			echo "Could not find '../$control_origtarname!" >&2
			echo "Without that file dpkg-source will not work!" >&2
			echo "(Have you forgotten to run prepare?)" >&2
			status_ret=4
		fi
	else
		debugout "Missing debian/.git-dpm makes further checks impossible"
		status_ret=3
	fi
	if $cancheckdebian ; then
		debugout "Checking if debian branch contains changes outside debian/ ..."
		checkdebian || status_ret=4
	fi
	if [ "$status_ret" -eq 0 ] ; then
		echo "git-dpm: everything up to date"
	else
		debugout "status returning with code $status_ret"
	fi
	return $status_ret
}

######### common stuff ##############

# check if commit $1 has the same message as in file $2,
# i.e. if the old commit can be reused (if tree already checked)
function checkcommitmessage() {
# "$candidate" "$gitdir/dpm/patch-log"
	gitcmd cat-file commit "$1" | sed -e '1,/^$/d' > "$gitdir"/dpm/oldmessage
	diff -a -w "$gitdir"/dpm/oldmessage "$2" # > /dev/null
}

# patchname, patch_author patch_fallbackauthor patch_date must be set (or empty)
# the patch already be in "$gitdir"/dpm/patchfile
# old_commit_count must be 0 or $gitdir/dpm/oldcommits existing and forcecommitreuse set
# may be called in a way set -e is not effective...
function apply_patch() {
	inpatchedbranch="$1"
	# parse patch before switching, as the checkout might remove the file.
	debugout "Parse $patchname..."
	rm -f "$gitdir/dpm/patch-author" "$gitdir/dpm/patch-date" "$gitdir/dpm/patch-subject" "$gitdir/dpm/patch-needs-repair" || return 1
	LC_ALL=C awk '
		BEGIN {fname=ARGV[1];ARGV[1]="";level=ARGV[2];ARGV[2]="";inpatch=0;hasheader=0}
		/^---/ { hasheader=1 ; inpatch=1 ; next }
		hasheader == 0 && inpatch && /^@@/ { print "gitneedshelp" > fname "-needs-repair" }
		inpatch { next }
		/^index [0-9a-f]+\.\.[0-9a-f]+ [0-7]+$/ \
		|| /^Index: [^ 	]*\/[^ 	]*$/ \
		|| (level == 0 && /^Index: [^ 	]*$/) \
		|| /^diff --git / \
	       	{ inpatch=1 ; next }
		afterheader { print ; next }
		/^[ 	]*$/ { afterheader=1 ; print ; next }
		/^From [0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f] / { next}
		/^Date: /  { gsub(/^Date: */,"") ; print > fname "-date" ; next}
		/^Author: /  { gsub(/^Author: */,"") ; print >> fname "-author" ; next}
		/^From: /  { gsub(/^From: */,"") ; print >> fname "-author" ; next}
		/^Subject: /  { gsub(/^Subject: *(\[[^]]*\] *)*/,"") ; print >> fname "-subject" ; next}
		/^Description: /  {gsub(/^Description: */,"") ; print >> fname "-subject" ; next}
		{ print ; next }
'	 "$gitdir/dpm/patch" "${level#-p}" "$gitdir/dpm/patchfile" > "$gitdir/dpm/patch-parsed" || return 1

	( if test -f "$gitdir/dpm/patch-subject" ; then
		cat "$gitdir/dpm/patch-subject" || return 1
	  else
		echo "${patchname%%.patch}"
	  fi
	  cat "$gitdir/dpm/patch-parsed" || return 1
	) > "$gitdir/dpm/patch-log"
	if test -n "$patch_author" ; then
		author="$(expr "z$patch_author" : 'z\(.*[^ ]\) *<.*')" || return 1
		email="$(expr "z$patch_author" : '.*<\([^>]*\)')" || return 1
		debugout "using Author: $author <$email>"
	elif test -f "$gitdir/dpm/patch-author" ; then
		pa="$(cat "$gitdir/dpm/patch-author")" || return 1
		author="$(expr "z$pa" : 'z\(.*[^ ]\) *<.*')" || return 1
		email="$(expr "z$pa" : '.*<\([^>]*\)')" || return 1
		debugout "determined Author: $author <$email>"
	elif test -n "$patch_fallbackauthor" ; then
		author="$(expr "z$patch_fallbackauthor" : 'z\(.*[^ ]\) *<.*')" || return 1
		email="$(expr "z$patch_fallbackauthor" : '.*<\([^>]*\)')" || return 1
		debugout "using default Author: $author <$email>"
	else
		author=""
		email=""
	fi
	if test -f "$gitdir/dpm/patch-date" ; then
		date="$(cat "$gitdir/dpm/patch-date")" || return 1
		debugout "using Date: $date"
	fi

	if $inpatchedbranch ; then
		# switch do patched branch if not already there:
		if test -z "$PATCHEDREV" ; then
			debugout "Creating patched branch '$PATCHEDBRANCH'..."
			gitcmd checkout -b "$PATCHEDBRANCH" "$control_patched" || return 1
			PATCHEDREV="$control_patched"
			HEADBRANCH="$PATCHEDBRANCH"
		elif [ x"$PATCHEDBRANCH" = x"$HEADBRANCH" ] ; then
			debugout "already in '$PATCHEDBRANCH', no need to switch"
		else
			gitcmd checkout "$PATCHEDBRANCH" || return 1
			HEADBRANCH="$PATCHEDBRANCH"
		fi
	fi

	debugout "Applying patch..."
	if test -f "$gitdir/dpm/patch-needs-repair" ; then
		debugout "Preprocessing patch to make sure git accepts it"
		awk ' BEGIN {headermissing = 1}
			/^Index: / {
				lastindex = gensub(/^Index: /,"","");
				headermissing = 1 }
			/^+++/ || /^---/ { headermissing = 0 }
			/^@@/ && headermissing {
				print "--- " lastindex
				print "+++ " lastindex
				headermissing = 0;
			}
			{ print ; next }
		 ' "$gitdir/dpm/patchfile" \
		 | gitcmd apply --index -C${lines_must_match} $level || return 1
	else
		gitcmd apply --index -C${lines_must_match} $level "$gitdir/dpm/patchfile" || return 1
	fi
	debugout "Creating commit..."
	tree="$(gitcmd write-tree)"
	if "$patch_edit" ; then
		sensible-editor "$gitdir/dpm/patch-log" || return 1
	fi
	if $inpatchedbranch ; then
		parent="$PATCHEDREV"
	else
		parent="$(gitcmd rev-parse HEAD)" || return 1
	fi
	commit=""
	if [ "$old_commit_count" -gt 0 ] ; then
		candidate="$(recycle_commit "$tree" "$parent")" || return 1
		if test -z "$candidate" ; then
			debugout "Cannot reuse old commit $candidate, creating new commit"
		elif $forcecommitreuse || checkcommitmessage "$candidate" "$gitdir/dpm/patch-log" ; then
			debugout "Reusing old commit $candidate"
			commit="$candidate"
		else
			debugout "Old commit had same tree but different message, creating new commit"
		fi
	fi
	if test -z "$commit" ; then
		commit="$(if test -n "$author" ; then export GIT_AUTHOR_NAME="$author" ; fi ;
	          if test -n "$email" ; then export GIT_AUTHOR_EMAIL="$email" ; fi ;
	          if test -n "$date" ; then export GIT_AUTHOR_DATE="$date" ; fi ;
	          gitcmd commit-tree "$tree" -p "$parent" \
		  < "$gitdir/dpm/patch-log" )" || return 1
	fi
	if $inpatchedbranch ; then
		gitcmd update-ref -m "git-dpm: import $patchname" HEAD "$commit" "$PATCHEDREV" || return 1
		PATCHEDREV="$commit"
	else
		gitcmd checkout -q "$commit" || return 1
	fi
	if $delete_temp_files ; then
		rm "$gitdir"/dpm/patch*
	fi
	return 0
}

# patchname, patch_author patch_fallbackauthor patch_date must be set (or empty)
# the patch already be in "$gitdir"/dpm/patchfile
# old_commit_count must be 0 or $gitdir/dpm/oldcommits existing and forcecommitreuse set
# may be called in a way set -e is not effective...
function apply_cdbs_patch() {
	# parse patch before switching, as the checkout might remove the file.
	debugout "Parse $patchname..."
	rm -f "$gitdir/dpm/patch-author" "$gitdir/dpm/patch-date" "$gitdir/dpm/patch-subject" || return 1
	# This is how simple-patchsys.mk gets the level, don't ask me...
	level="$(head "$gitdir/dpm/patchfile" | egrep '^#DPATCHLEVEL=' | cut -f 2 -d '=')" || return 1
	if test -n "$level" ; then
		debugout "Level determined to be $level"
	fi
	LC_ALL=C awk '
		BEGIN {fname=ARGV[1];ARGV[1]="";inpatch=0}
		inpatch { next }
		/^#DPATCHLEVEL=/ { next ; }
		/^---/ \
		|| /^index [0-9a-f]+\.\.[0-9a-f]+ [0-7]+$/ \
		|| /^Index: [^ 	]*\/[^ 	]*$/ \
		|| /^diff --git / \
	       	{ inpatch=1 ; next }
		afterheader { print ; next }
		/^[ 	]*$/ { afterheader=1 ; print ; next }
		/^From [0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f] / { next}
		/^Date: /  { gsub(/^Date: */,"") ; print > fname "-date" ; next}
		/^Author: /  { gsub(/^Author: */,"") ; print >> fname "-author" ; next}
		/^From: /  { gsub(/^From: */,"") ; print >> fname "-author" ; next}
		/^Subject: /  { gsub(/^Subject: *(\[[^]]*\] *)*/,"") ; print >> fname "-subject" ; next}
		/^Description: /  {gsub(/^Description: */,"") ; print >> fname "-subject" ; next}
		{ print ; next }
'	 "$gitdir/dpm/patch" "$gitdir/dpm/patchfile" > "$gitdir/dpm/patch-parsed" || return 1

	( if test -f "$gitdir/dpm/patch-subject" ; then
		cat "$gitdir/dpm/patch-subject" || return 1
	  else
		echo "${patchname%%.patch}"
	  fi
	  cat "$gitdir/dpm/patch-parsed"
	) > "$gitdir/dpm/patch-log" || return 1
	if test -n "$patch_author" ; then
		author="$(expr "z$patch_author" : 'z\(.*[^ ]\) *<.*')" || return 1
		email="$(expr "z$patch_author" : '.*<\([^>]*\)')" || return 1
		debugout "using Author: $author <$email>"
	elif test -f "$gitdir/dpm/patch-author" ; then
		pa="$(cat "$gitdir/dpm/patch-author")" || return 1
		author="$(expr "z$pa" : 'z\(.*[^ ]\) *<.*')" || return 1
		email="$(expr "z$pa" : '.*<\([^>]*\)')" || return 1
		debugout "determined Author: $author <$email>"
	elif test -n "$patch_fallbackauthor" ; then
		author="$(expr "z$patch_fallbackauthor" : 'z\(.*[^ ]\) *<.*')" || return 1
		email="$(expr "z$patch_fallbackauthor" : '.*<\([^>]*\)')" || return 1
		debugout "using default Author: $author <$email>"
	else
		author=""
		email=""
	fi
	if test -f "$gitdir/dpm/patch-date" ; then
		date="$(cat "$gitdir/dpm/patch-date")" || return 1
		debugout "using Date: $date"
	fi

	# switch do patched branch if not already there:
	if test -z "$PATCHEDREV" ; then
		debugout "Creating patched branch '$PATCHEDBRANCH'..."
		gitcmd checkout -b "$PATCHEDBRANCH" "$control_patched" || return 1
		PATCHEDREV="$control_patched"
		HEADBRANCH="$PATCHEDBRANCH"
	elif [ x"$PATCHEDBRANCH" = x"$HEADBRANCH" ] ; then
		debugout "already in '$PATCHEDBRANCH', no need to switch"
	else
		gitcmd checkout "$PATCHEDBRANCH" || return 1
		HEADBRANCH="$PATCHEDBRANCH"
	fi

	if test -n "$level" ; then
		debugout "Applying patch with level ${level} ..."
		gitcmd apply --index -C${lines_must_match} -p$level "$gitdir/dpm/patchfile" || return 1
	else
		debugout "Applying patch.. testing first level 1..."
		if gitcmd apply --index -C${lines_must_match} -p1 "$gitdir/dpm/patchfile" ; then
			debugout "level 1 worked"
		else
			echo "Could not apply $patchname with level 1, trying 0..."
			if gitcmd apply --index -C${lines_must_match} -p0 "$gitdir/dpm/patchfile" ; then
				debugout "level 0 worked"
			else
				echo "Could not apply $patchname with level 1, trying 0..."
				if gitcmd apply --index -C${lines_must_match} -p2 "$gitdir/dpm/patchfile" ; then
					debugout "level 2 worked"
				else
					printerror "Could not apply $patchname with neither level 1, 0 nor 2."
					return 1
				fi
			fi
		fi
	fi
	debugout "Creating commit..."
	tree="$(gitcmd write-tree)"
	if "$patch_edit" ; then
		sensible-editor "$gitdir/dpm/patch-log" || return $?
	fi
	parent="$PATCHEDREV"
	commit=""
	if [ "$old_commit_count" -gt 0 ] ; then
		candidate="$(recycle_commit "$tree" "$parent")" || return 1
		if test -z "$candidate" ; then
			debugout "Cannot reuse old commit $candidate, creating new commit"
		elif $forcecommitreuse || checkcommitmessage "$candidate" "$gitdir/dpm/patch-log" ; then
			debugout "Reusing old commit $candidate"
			commit="$candidate"
		else
			debugout "Old commit had same tree but different message, creating new commit"
		fi
	fi
	if test -z "$commit" ; then
		commit="$(if test -n "$author" ; then export GIT_AUTHOR_NAME="$author" ; fi ;
	          if test -n "$email" ; then export GIT_AUTHOR_EMAIL="$email" ; fi ;
	          if test -n "$date" ; then export GIT_AUTHOR_DATE="$date" ; fi ;
	          gitcmd commit-tree "$tree" -p "$parent" \
		  < "$gitdir/dpm/patch-log" )" || return 1
	fi
	gitcmd update-ref -m "git-dpm: import $patchname" HEAD "$commit" "$PATCHEDREV" || return 1
	PATCHEDREV="$commit"
	if $delete_temp_files ; then
		rm "$gitdir"/dpm/patch*
	fi
	return 0
}

######### apply-patch ##############

function do_apply_patch() {
	patch_author=""
	patch_fallbackauthor=""
	patch_date=""
	patch_edit=false
	is_dpatch_patch=false
	is_cdbs_patch=false
	while [ $# -gt 0 ] ; do
		case "$1" in
			--help)
				cat <<'EOF'
Syntax: git-dpm [global options] apply-patch [options] [<patch>]
 Import a patch to the patched branch. (Without filename, stadin is used).
Possible local options:
 --default-author "name <email>":
   If no author information can be extracted from the patch, use this.
 --author "name <email>":
   Explicitly give author information.
 --date <date>:
   Explicitly set the date.
 --context <number>
   Require at least <number> lines of context to match. (Default 1)
 --cdbs:
   Parse patch as cdbs simple-makesys patch file.
 --dpatch:
   Parse patch as dpatch patch file.
 --edit:
   edit the preprocessed patch before applying
EOF
				return 0
				;;
			--dpatch)
				is_dpatch_patch=true
				;;
			--cdbs)
				is_cdbs_patch=true
				;;
			--context|--patch-context|-C)
				shift
				lines_must_match="$1"
				;;
			-C*|--context=*|--patch-context=*)
				lines_must_match="${1#-C}"
				lines_must_match="${lines_must_match#--context=}"
				lines_must_match="${lines_must_match#--patch-context=}"
				;;
			--author)
				shift
				patch_author="$1"
				;;
			--author=*)
				patch_author="${1#--author=}"
				;;
			--defaultauthor|--default-author)
				shift
				patch_fallbackauthor="$1"
				;;
			--defaultauthor=*|--default-author=*)
				patch_fallbackauthor="${1#--defaultauthor=}"
				patch_fallbackauthor="${patch_fallbackauthor#--default-author=}"
				;;
			--date)
				shift
				patch_date="$1"
				;;
			--date=*)
				patch_date="${1#--date=}"
				;;
			--edit)
				patch_edit=true
				;;
			--dpatch-allow-empty)
				dpatch_forbid_empty=false
				;;
			--)
				shift
				break
				;;
			-*)
				printerror "Unrecognised tag option '$1'!"
				return 1
				;;
			*)
				break
				;;
		esac
		shift
	done
	if $is_cdbs_patch && $is_dpatch_patch ; then
		printerror "--cdbs and --dpatch are incompatible..."
		return 1
	fi
	level=""
	filename="-"
	if [ $# -gt 0 ] ; then
		filename="$1"
		shift
	fi
	if [ $# -gt 0 ] ; then
		printerror "Unexpected arguments '$*'!"
		return 1
	fi
	checkgitdir
	rm -f -- "$gitdir"/dpm/patch*
	if [ x"$filename" = x"-" ] ; then
		cat > "$gitdir"/dpm/patchfile
		patchname=""
	else
		patchname="$(basename -- "$filename")"
		cp -- "$filename"  "$gitdir"/dpm/patchfile
	fi
	cdtoplevel
	initbranchvariables
	parsedpmcontrolfile ""
	checkclean $allow_nonclean

	old_commit_count=0
	if $is_cdbs_patch ; then
		apply_cdbs_patch
	elif $is_dpatch_patch ; then
		apply_dpatch_patch
	else
		apply_patch true
	fi
	echo "patch applied to '$PATCHEDBRANCH' branch."
	echo "Don't forget to call update-patches after you are done."
	return 0
}

######### apply-dpatch-patch ##############

# patchname, patch_author patch_fallbackauthor patch_date must be set (or empty)
# the patch already be in "$gitdir"/dpm/patchfile
# old_commit_count must be 0 or $gitdir/dpm/oldcommits existing and forcecommitreuse set
# may be called in a way set -e is not effective...
function apply_dpatch_patch() {
	# parse patch before switching, as the checkout might remove the file.
	debugout "Parse $patchname as dpatch patch..."
	ret=0
	rm -f "$gitdir/dpm/patch-author"
	rm -f "$gitdir/dpm/patch-unpack-command"
	LC_ALL=C awk '
		BEGIN {fname=ARGV[1];ARGV[1]="";inpatch=0}
		inpatch { next }
		FNR == 1 && !/^#! \/bin\/sh/ {
			exit 3
		}
		FNR == 2 && !/^## .*\.dpatch by .*/ {
			exit 3
		}
		FNR == 2 {
			gsub(/.*\.dpatch by /,"");
			print >> fname "-author" ;
			next
		}
		/^## DP: / { gsub(/^## DP: /,"") ; print ; next}
		/^[ 	]*-patch) patch/ { print >> fname "-unpack-command" ; next}
		/^---/ \
		|| /^index [0-9a-f]+\.\.[0-9a-f]+ [0-7]+$/ \
		|| /^Index: [^ 	]*\/[^ 	]*$/ \
		|| /^diff --git / \
		|| /^@DPATCH@$/ \
	       	{ inpatch=1 ; next }
		{ next }
'	 "$gitdir/dpm/patch" "$gitdir/dpm/patchfile" > "$gitdir/dpm/patch-log" || ret=$?
	if [ $ret = 3 ] ; then
		printerror "$patchname" does not look like a dpatch file
		return 1
	fi
	if [ $ret != 0 ] ; then
		return 1
	fi
	level=""
	if test -f "$gitdir/dpm/patch-unpack-command" ; then
		level="-p$(sed -n '1s/.* -p\([0-9]*\) .*/\1/p' "$gitdir/dpm/patch-unpack-command")" || return 1
	fi
	if ! test -s "$gitdir/dpm/patch-log" || ! grep -q -v '^No description\.$' -- "$gitdir/dpm/patch-log" ; then
		echo "${patchname}" | sed -e 's/^[0-9]\+_//' > "$gitdir/dpm/patch-log"
	fi
	if test -n "$patch_author" ; then
		author="$(expr "z$patch_author" : 'z\(.*[^ ]\) *<.*')" || return 1
		email="$(expr "z$patch_author" : '.*<\([^>]*\)')" || return 1
		debugout "using Author: $author <$email>"
	elif test -f "$gitdir/dpm/patch-author" ; then
		pa="$(cat "$gitdir/dpm/patch-author")" || return 1
		author="$(expr "z$pa" : 'z\(.*[^ ]\) *<.*')" || return 1
		email="$(expr "z$pa" : '.*<\([^>]*\)')" || return 1
		debugout "determined Author: $author <$email>"
	elif test -n "$patch_fallbackauthor" ; then
		author="$(expr "z$patch_fallbackauthor" : 'z\(.*[^ ]\) *<.*')" || return 1
		email="$(expr "z$patch_fallbackauthor" : '.*<\([^>]*\)')" || return 1
		debugout "using default Author: $author <$email>"
	else
		author=""
		email=""
	fi
	# switch do patched branch if not already there:
	if test -z "$PATCHEDREV" ; then
		debugout "Creating patched branch '$PATCHEDBRANCH'..."
		gitcmd checkout -b "$PATCHEDBRANCH" "$control_patched" || return 1
		PATCHEDREV="$control_patched"
		HEADBRANCH="$PATCHEDBRANCH"
	elif [ x"$PATCHEDBRANCH" = x"$HEADBRANCH" ] ; then
		debugout "already in '$PATCHEDBRANCH', no need to switch"
	else
		gitcmd checkout "$PATCHEDBRANCH" || return 1
		HEADBRANCH="$PATCHEDBRANCH"
	fi

	debugout "Applying patch..."
	gitcmd apply --index -C${lines_must_match} $level "$gitdir/dpm/patchfile" || return 1
	debugout "Creating commit..."
	tree="$(gitcmd write-tree)" || return 1
	if [ x"$tree" = x"$(gitcmd rev-parse ${PATCHEDREV}:)" ] && $dpatch_forbid_empty ; then
		printerror "Error importing ${patchname}.dpatch: No changes."
		echo "Either this is an empty patch (force processing with --dpatch-allow-empty)" >&2
		echo "Or this is not a patch but a dpatch script which is not supported" >&2
		return 1
	fi
	if "$patch_edit" ; then
		sensible-editor "$gitdir/dpm/patch-log" || return $?
	fi
	commit=""
	if [ "$old_commit_count" -gt 0 ] ; then
		candidate="$(recycle_commit "$tree" "$PATCHEDREV")" || return 1
		if test -z "$candidate" ; then
			debugout "Cannot reuse old commit $candidate, creating new commit"
		elif $forcecommitreuse || checkcommitmessage "$candidate" "$gitdir/dpm/patch-log" ; then
			debugout "Reusing old commit $candidate"
			commit="$candidate"
		else
			debugout "Old commit had same tree but different message, creating new commit"
		fi
	fi
	if test -z "$commit" ; then
		# create new commit
		commit="$(if test -n "$author" ; then export GIT_AUTHOR_NAME="$author" ; fi ;
	          if test -n "$email" ; then export GIT_AUTHOR_EMAIL="$email" ; fi ;
	          gitcmd commit-tree "$tree" -p "$PATCHEDREV" \
		  < "$gitdir/dpm/patch-log" )" || return 1
	fi
	gitcmd update-ref -m "git-dpm: import ${patchname}.dpatch" HEAD "$commit" "$PATCHEDREV" || return 1
	PATCHEDREV="$commit"
	if $delete_temp_files ; then
		rm "$gitdir"/dpm/patch*
	fi
	return 0
}
######### import-tar ############

function import_tar() {
	commit=""
	filename="$1"
	parents="$2"
	parent_commits="$3"
	commit_msg="${4:-}"

	# This is a bit over-cautionous, perhaps not only a bit.
	# But if anything of the following fails, I do not want to end
	# up with a commit having deleted everything...

	# a pity that git is so strange w.r.t to the empty tree
	if ! $emptytreeexists && ! gitcmd cat-file -e "4b825dc642cb6eb9a060e54bf8d69288fbee4904" ; then
		debugout "Git-Internalizing the empty tree..."
		# in a newly git-init'ed repository git rm -r . does not work,
		# but in that case the index is already empty...
		oldtree="$(gitcmd write-tree)"
		if [ x"$oldtree" != x"4b825dc642cb6eb9a060e54bf8d69288fbee4904" ] ; then
			# only set the index not the working dir
			gitcmd rm -f --cached -r -q .
			emptytree="$(gitcmd write-tree)"
			# reset the index (so the checkout will remove the files)
			gitcmd read-tree "$oldtree"
			if [ x"$emptytree" != x"4b825dc642cb6eb9a060e54bf8d69288fbee4904" ] ; then
				printerror "Failed to create the empty tree."
				return 1
			fi
		fi
	fi
	emptytreeexists=true

	# 4b825dc642cb6eb9a060e54bf8d69288fbee4904 is the sha of the empty tree.
	# Is is always know to git.
	emptycommit=$(echo "Empty Tree - to avoid things deleted at the wrong place" | gitcmd commit-tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904 )
	debugout "Create detached empty HEAD..."
	gitcmd checkout -q "$emptycommit"
	HEADBRANCH="DETACHED"

	debugout "Unpack '$filename' and import into git's index".
	# TODO: allow excluding file...
	# TODO: allow another strip-components value
	# TODO: This requires that tar only prints filenames after they are finished.
	# verify that this is true or first put it into an temporary file...
#	tar --exclude=.git --force-local --no-same-owner --no-same-permissions -U -xvf "$filename" | LC_ALL=C grep -v '/$' | gitcmd update-index --add --stdin
	tar --exclude=.git --force-local --no-same-owner --no-same-permissions -U -xvvf "$filename" | LC_ALL=C sed -n -e 's/^-.........[ 	]\+[^ 	]\+[ 	]\+[^ 	]\+[ 	]\+[^ 	]\+[ 	]\+[^ 	]\+[ 	]\+\(.*\)$/\1/p' | gitcmd update-index --add --stdin
	# it would be nice to have used --strip-components, but they would have still
	# appeared in the output, needing filtering there...
	tree="$(gitcmd write-tree)"
	if [ 1 -eq $(gitcmd ls-tree "$tree" | wc -l) ] &&
	   gitcmd ls-tree "$tree" | LC_ALL=C grep -q -s '^[0-7]* tree ' ; then
		tree="$(gitcmd rev-parse --verify "$tree":"$(gitcmd ls-tree --name-only "$tree")")"
	fi
	if test -n "$commit_msg" ; then
		commit="$(echo "$commit_msg" | gitcmd commit-tree "$tree" $parents)"
	else
		echo "Import $(basename -- "$filename")" > "$gitdir"/dpm/import-tar.txt
		for parent in $parent_commits ; do
			echo >> "$gitdir"/dpm/import-tar.txt
			echo "# differences relative to $parent:" \
				>> "$gitdir"/dpm/import-tar.txt
			echo >> "$gitdir"/dpm/import-tar.txt
			gitcmd diff --stat "$parent" "$tree" \
				| sed -e 's/^/# /' >> "$gitdir"/dpm/import-tar.txt
		done
		sensible-editor "$gitdir"/dpm/import-tar.txt
		commit="$(LC_ALL=C grep -v '^#' "$gitdir"/dpm/import-tar.txt | gitcmd commit-tree "$tree" $parents)"
		if $delete_temp_files ; then
			rm -- "$gitdir/dpm/import-tar.txt"
		fi
	fi

	gitcmd checkout -q -f "$commit"
	#returns commit id in $commit
	return 0
}

function add_parent() {
	if ! gitcmd rev-parse -q --verify "$1" > /dev/null ; then
		printerror "'$1' is not known by git."
		return 1
	fi
	parents="$parents -p $1"
	parent_commits="$parent_commits $1"
}

function do_import_tar() {
	parents=""
	parent_commits=""
	# empty message means start an editor
	commit_msg=""
	while [ $# -gt 0 ] ; do
		case "$1" in
			--help)
				cat <<'EOF'
Syntax: git-dpm [global options] import-tar [ -p <parent> ]*  <tar file to import>
 Create a new git commit with the contents of the given targfile as contents and
 with the given parents as parents. (Without parents, it will be a root node).

 The new commit will be checked out as detached HEAD. Use "git checkout -b name"
 to name it afterwards.
EOF
				return 0
				;;
			-p|--parent)
				shift
				add_parent "$1" || return 1
				;;
			--parent=*)
				add_parent "${1#--parent=}" || return 1
				;;
			-m|--message)
				shift
				commit_msg="$1"
				;;
			--message=*)
				commit_msg="${1#--message=}"
				;;
			--)
				shift
				break
				;;
			-*)
				printerror "Unrecognised import-tar option '$1'!"
				return 1
				;;
			*)
				break
				;;
		esac
		shift
	done
	if [ $# -lt 1 ] ; then
		cat >&2 <<'EOF'
Syntax: git-dpm [global options] import-tar [ -p <parent> ]* <tarfile to import>
EOF
		return 1
	fi
	filename="$1"
	shift
	if ! [ -f "$filename" ] ; then
		printerror "no such file: '$filename'!"
		return 1
	fi
	if [ $# -gt 0 ] ; then
		printerror "Unexpected import-tar argument: '$filename'!"
		return 1
	fi

	checkgitdir
	cdtoplevel
	checkclean $allow_nonclean

	import_tar "$filename" "$parents" "$parent_commits" "$commit_msg"
	# returns commit in commit, should also be detached HEAD...

	echo "You are now in a detached head with the new commit."
	echo "(To store that in a branch, use git checkout -b NEWNAME)"
	return 0
}

function do_import_new_upstream() {
	parents=""
	parent_commits=""
	connectoldupstream=true
	dorebase=false
	wrongupstreambranchiserror=true
	wrongpatchedbranchiserror=true
	while [ $# -gt 0 ] ; do
		case "$1" in
			--help)
				cat <<'EOF'
Syntax: git-dpm [global options] import-new-upstream [options] <.orig.tar file to import>
 Import and record a new upstream tarball. (If you do not want to have the
 whole tarball imported, prepare a suiteable upstream branch yourself and
 use git-dpm new-upstream instead).

Possible local options:
 -p parent:
  Add the given parent as parent. (Can be given multiple time).
  You can include upstream's history by naming the branch you have upstream's
  commit for that version.
 --detached:
  Do not add the old upstream branch as parent.
 --rebase-patched:
   Call git-dpm rebase-patched afterwards to rebase possible patches to the
   new upstream.
 --use-strange-upstream-branch:
 --use-strange-patched-branch:
   Discard any possible local changes to (or not automatically detected stale
   states of ) the branches
EOF
				return 0
				;;
			-p|--parent)
				shift
				add_parent "$1" || return 1
				;;
			--parent=*)
				add_parent "${1#--parent=}" || return 1
				;;
			--detached)
				connectoldupstream=false
				;;
			--rebase-patched|--rebase)
				dorebase=true
				;;
			--use-strange-upstream-branch)
				wrongupstreambranchiserror=false
				;;
			--use-strange-patched-branch)
				wrongpatchedbranchiserror=false
				;;
			--)
				shift
				break
				;;
			-*)
				printerror "Unrecognised import-new-upstream option '$1'!"
				return 1
				;;
			*)
				break
				;;
		esac
		shift
	done
	if [ $# -lt 1 ] ; then
		cat >&2 <<'EOF'
Syntax: git-dpm [global options] import-new-upstream [ --detached ] [ -p <parent> ]* <.orig.tar file to import>
EOF
		return 1
	fi

	origfilename="$1"
	shift
	if ! [ -f "$origfilename" ] ; then
		printerror "no such file: '$origfilename'!"
		return 1
	fi
	origname=${origfilename##*/}
	case "$origname" in
		*.orig.tar.*)
			;;
		*)
			printerror "'$origname' does not contain .orig.tar!"
			return 1
			;;
	esac
	debugout "look at '$origfilename'..."
	origsha="$(sha1sum -b -- "$origfilename")"
	origsha="${origsha%% *}"
	origsize="$(stat --printf '%s' "$origfilename")"

	checkgitdir
	initbranchvariables
	cdtoplevel
	checkclean $allow_nonclean
	parsedpmcontrolfile ""

	if test -n "$UPSTREAMREV" ; then
		if $connectoldupstream && [ x"$UPSTREAMREV" != x"$control_upstream" ] ; then
			if $wrongupstreambranchiserror ; then
				printerror "'$UPSTREAMBRANCH' differs from recorded '$control_upstream'!. Delete that branch or use --use-strange-upstream-branch to use anyway."
				return 1
			else
				printwarn "Using unrecorded '$UPSTREAMBRANCH'."
			fi
		fi
		upstream="$UPSTREAMBRANCH"
	else
		upstream="$control_upstream"
	fi
	if $dorebase && test -n "$PATCHEDREV" &&
	   [ x"$PATCHEDREV" != x"$control_patched" ] &&
	   $wrongpatchedbranchiserror ; then
		printerror "'$PATCHEDBRANCH' differs from recorded '$control_patched'!"
		echo "If that branch is in some old state, delete it." >&2
		echo "If you have unrecorded changes there you want to use for the new version, use --use-strange-patched-branch."
		return 1
	fi

	if $connectoldupstream ; then
		parents="-p $upstream $parents"
		parent_commits="$upstream $parent_commits"
	fi
	import_tar "$origfilename" "$parents" "$parent_commits" ""
	# returns commit in commit, should also be detached HEAD...

	debugout "setting upstream branch..."
	if test -n "$UPSTREAMREV" ; then
		gitcmd update-ref -m "imported $origname" refs/heads/"$UPSTREAMBRANCH" "$commit" "$UPSTREAMREV"
		gitcmd checkout "$UPSTREAMBRANCH"
	else
		gitcmd checkout -b "$UPSTREAMBRANCH"
	fi
	UPSTREAMREV="$commit"
	HEADBRANCH="$UPSTREAMBRANCH"

	# TODO: option to call pristine-tar for you?

	debugout "Record new upstream branch..."
	record_new_upstream_branch false false
	if $dorebase ; then
		debugout "Calling rebase-patched..."
		rebase_patches
	else
		echo "Next you need to call git-dpm rebase-patched (even if there are no patches)"
	fi
}

########## import-dsc ############

function parse_dsc() {
	dscfilename="$1"
	shift
	if ! test -f "$dscfilename" ; then
		printerror "Cannot find $dscfilename"
		return 1
	fi
	# Quick & Dirty .dsc parser:
	debugout "Parsing .dsc file $dscfilename"
	fsource="$(grep "^Source: " "$dscfilename" || echo non-found)"
	fsource="${fsource#Source: }"
	case "$fsource" in
		(non-found)
			printerror "Missing Source in $dscfilename"
			return 1
			;;
		("* *")
			printerror "Cannot parse Source header in $dscfilename"
			return 1
			;;
	esac
	debugout "Name determined to be '$fsource'"
	fversion="$(grep "^Version: " "$dscfilename" | head -n 1 || echo non-found)"
	fversion="${fversion#Version: }"
	case "$fversion" in
		(non-found)
			printerror "Missing Version in $dscfilename"
			return 1
			;;
		("* *")
			printerror "Cannot parse Version header in $dscfilename"
			return 1
			;;
	esac
	fileversion="${fversion#*:}"
	origfileversion="${fileversion%-*}"
	debugout "Version determined to be '$fversion', without epoch '$fileversion', without epoch and revision '$origfileversion'"
	fformat="$(grep "^Format:" "$dscfilename" || echo non-found)"
	case "$fformat" in
		(non-found)
			printerror "$dscfilename does not look like a .dsc (missing Format)"
			return 1
			;;
		("Format: 1.0")
			format="old"
			;;
		("Format: 3.0 (native)")
			format="native"
			;;
		("Format: 3.0 (quilt)")
			format="quilt"
			;;
		("*")
			printerror "Unsupported format '${fformat#Format: }' of $dscfilename"
			return 1
			;;
	esac
	debugout "Format determined: $format"
	awk 'BEGIN { infiles = 0} \
	     /^Files:[ 	]*/ {infiles = 1 ; next} \
	     /^ / && infiles { print ; next} \
	     { infiles = 0 ; next } \
	    ' "$dscfilename" > "$gitdir"/dpm/dscfiles
	foundorigfilename=""
	foundnativefilename=""
	founddifffilename=""
	founddebianfilename=""
	while read md5sum size filename rest ; do
		if test -n "$rest" || test -z "$filename"; then
			printerror "Unparseable line in $dscfilename Files: $md5sum $size $filename $rest"
			return 1
		fi
		debugout "lists file '$filename'..."
		case "$filename" in
			(${fsource}_${fileversion}.tar.*)
				foundnativefilename="$filename"
				origsize="$size"
				;;
			(${fsource}_${origfileversion}.orig.tar.*)
				foundorigfilename="$filename"
				origsize="$size"
				;;
			(${fsource}_${fileversion}.debian.tar.*)
				founddebianfilename="$filename"
				;;
			(${fsource}_${fileversion}.diff.*)
				founddifffilename="$filename"
				;;
			(*)
				printerror "Unexpected file $filename in $dscfilename"
				if [ $format != old ] ; then
					# TODO:
					# (simply unpacking should work, though
					# there is no support to make sure they
					# exist when building, anyway...)
					echo "Note that 3.0's sub-tars (except .debian.tar) are not yet supported..."
				fi
				return 1
		esac
	done < "$gitdir"/dpm/dscfiles
	if $delete_temp_files ; then
		rm -- "$gitdir/dpm/dscfiles"
	fi
	quilt_build_deps=""
	# Fail out early, fail out often...
	case $format in
		(old)
			if test -n "$founddebianfilename" ; then
				printerror "$dscfilename is Format 1.0 but contains a .debian.tar"
				return 1
			fi
			if test -n "$founddifffilename" ; then
				if test -z "$foundorigfilename" ; then
					printerror "$dscfilename is Format 1.0 and containd a .diff but no .orig.tar was found"
					return 1
				fi
				if test -n "$foundnativefilename" ; then
					printerror "$dscfilename is Format 1.0 and containd a .diff but a non-orig .tar was found"
					return 1
				fi
				format=diff
			else
				if test -n "$foundorigfilename" ; then
					printerror "$dscfilename is Format 1.0 and containd no .diff but a .orig.tar"
					return 1
				fi
				if test -z "$foundnativefilename" ; then
					printerror "$dscfilename did not contain .diff nor .tar"
					return 1
				fi
				format=oldnative
			fi
			# make some guessing more realistic
			quilt_build_deps="$(awk 'BEGIN { inbd = 0}
			     inbd && ! /^ / { inbd = 0 ; next }
			     /^Build-Depends:/ {inbd = 1}
			     inbd == 0 { next }
			     /\<quilt\>/ { print "quilt" }
			     { next }
			    ' "$dscfilename")"
			;;
		(quilt)
			if test -z "$founddebianfilename" ; then
				printerror "$dscfilename is Format 3.0 (quilt), but no .debian.tar was found"
				return 1
			fi
			if test -z "$foundorigfilename" ; then
				printerror "$dscfilename is Format 3.0 (quilt), but no .orig.tar was found"
				return 1
			fi
			if test -n "$foundnativefilename" ; then
				printerror "$dscfilename is Format 3.0 (quilt), but a native .tar was found"
				return 1
			fi
			if test -n "$founddifffilename" ; then
				printerror "$dscfilename is Format 3.0 (quilt), but a .diff was found"
				return 1
			fi
			;;
		(native)
			if test -n "$founddebianfilename" ; then
				printerror "$dscfilename is Format 3.0 (native), but a .debian.tar was found"
				return 1
			fi
			if test -n "$foundorigfilename" ; then
				printerror "$dscfilename is Format 3.0 (native), but a .orig.tar was found"
				return 1
			fi
			if test -z "$foundnativefilename" ; then
				printerror "$dscfilename is Format 3.0 (native), but no native .tar was found"
				return 1
			fi
			if test -n "$founddifffilename" ; then
				printerror "$dscfilename is Format 3.0 (native), but a .diff was found"
				return 1
			fi
			;;
		(*)
			printerror "Confused (what is my format)?"
			return 1
	esac
}

function douncompress() {
	case "$1" in
		(*.diff|*.patch)
			cat "$1"
			;;
		(*.gz)
			gunzip -c "$1"
			;;
		(*.bz2)
			bunzip2 -c "$1"
			;;
		(*.lzma)
			unlzma -c "$1"
			;;
		(*.uu)
			uudecode -o - "$1"
			;;
		(*)
			printerror "Unsupported/unknown compression of $1"
			return 1
	esac
}

function recycle_commit() {
	LC_ALL=C sed -n -e 's/^\([^ ]*\) '"$1"' '"$2"'$/\1/p' -- "$gitdir"/dpm/oldcommits | head -n 1
}

# tree and parent must be full sha1-hex
function recycle_or_create_commit() {
	local message="$1"
	local tree="$2"
	local parent="$3"

	commit="$(recycle_commit "$tree" "$parent")"
	if test -z "$commit" ; then
		commit="$(echo "$message" | gitcmd commit-tree "$tree" -p "$parent")"
	fi
	# returns in $commit
}

# This function is called from if,
# so it and all functions called from it cannot rely on set -e
function import_patches_from_dsc() {
	# After importing a 1.0 format dsc,
	# by user choosing or autodetection
	# a quilt/dpatch/simple series to apply was detected.
	# Now import that:

	case $patch_system in
		(quilt)
			if ! test -f debian/patches/series ; then
				printwarn "No debian/patches/series file found. Assuming that means there are not patches..."
				return 0
			fi
			;;
		(dpatch)
			if ls debian/patches/00list.* 2>/dev/null ; then
				printwarn "There seem to be architecture dependent patches. Those will not be imported."
			fi
			if ! test -f debian/patches/00list ; then
				printwarn "No debian/patches/00list file found. Assuming that means there are not patches..."
				return 0
			fi
			;;
		(simple)
			rm -rf "$gitdir/dpm/import" || return 1
			mkdir "$gitdir/dpm/import" || return 1
			find debian/patches -type f -name "*.patch" \( -name "*.diff" -o -name "*.diff.gz" -o -name "*.diff.bz2" -o -name "*.diff.uu" -o -name "*.patch" -o -name "*.patch.gz" -o -name "*.patch.bz2" -o -name "*.patch.uu" \) -printf '%f\n' | sort > "$gitdir"/dpm/import/series || return 1
			no_patches=true
			while read filename ; do
				douncompress debian/patches/"$filename" >"$gitdir"/dpm/import/"$filename" || return 1
				no_patches=false
			done <"$gitdir/dpm/import/series"
			if $no_patches ; then
				printwarn "No patches found in debian/patches"
				if $delete_temp_files ; then
					rm -r "$gitdir/dpm/import"
				fi
				return 0
			fi
			;;
	esac
	if $apply_patches_first ; then
		patchedbase="$verbatimUPSTREAMREV"
		if [ x"$verbatimPATCHEDREV" != x"$verbatimUPSTREAMREV" ] ; then
			debugout "applying patches directly upon upstream"
		fi

	else
		patchedbase="$verbatimPATCHEDREV"
	fi
	PATCHEDREV="$patchedbase"
	gitcmd checkout -b "$PATCHEDBRANCH" "$PATCHEDREV" || return 1
	HEADBRANCH="$PATCHEDBRANCH"

	debugout "Trying to apply $patch_system patches found in the package..."

	case $patch_system in
		(quilt)
			apply_patches "" true || return 1
			;;
		(dpatch)
			apply_dpatch_patches || return 1
			;;
		(simple)
			while read patchname ; do
				echo "Applying '$patchname'..."
				cp "$gitdir"/dpm/import/"$patchname" "$gitdir"/dpm/patchfile || return 1
				patch_date=""
				apply_cdbs_patch || return 1
				debugout "patch $patchname applied..."
			done <"$gitdir/dpm/import/series"
			if $delete_temp_files ; then
				rm -r "$gitdir/dpm/import"
			fi
			echo "Note that the original patches will not be remove by update-patches, try running git rm -r debian/patches before the next git-dpm update-patches."
			;;
	esac

	if [ x"$PATCHEDREV" = x"$patchedbase" ] ; then
		printwarn "Strange - no patches were applied..."
		gitcmd checkout "$DEBIANBRANCH" || return 1
		HEADBRANCH="$DEBIANBRANCH"
		gitcmd branch -d "$PATCHEDBRANCH" || return 1
		PATCHEDREV=""
		return 0
	fi
	imported_patches=true
	if $apply_patches_first && [ x"$verbatimPATCHEDREV" != x"$verbatimUPSTREAMREV" ] ; then
		if $preapplied_patches ; then
			difftree="$(gitcmd rev-parse "$verbatimPATCHEDREV":)"
			if [ x"$(gitcmd rev-parse "$PATCHEDREV":)" = x"$difftree" ] ; then
				debugout "All changes in the diff were already in debian/patches/"
			else
				debugout "Adding an additional patch setting the tree to what was found in .diff"
				recycle_or_create_commit "Changes found in $founddifffilename" "$difftree" "$PATCHEDREV"
				gitcmd checkout -q "$commit" || return 1
				gitcmd update-ref refs/heads/"$PATCHEDBRANCH" "$commit" "$PATCHEDREV" || return 1
				PATCHEDREV="$commit"
				gitcmd checkout -q "$PATCHEDBRANCH" || return 1
			fi
		else
			echo "Try to pick the differences found in .diff on top of the patches"
			gitcmd cherry-pick -r "$verbatimPATCHEDREV" || return 1
			commit="$(recycle_commit "$(gitcmd rev-parse HEAD:)" "$PATCHEDREV")"
			if test -n "$commit" ; then
				debugout "can reuse old commit instead..."
				gitcmd checkout -q "$commit" || return 1
				gitcmd update-ref refs/heads/"$PATCHEDBRANCH" "$commit" || return 1
				PATCHEDREV="$commit"
				gitcmd checkout -q "$PATCHEDBRANCH" || return 1
			else
				PATCHEDREV="$(gitcmd rev-parse HEAD)"
			fi
		fi
	fi

	debugout "Merge those changes into $DEBIANBRANCH..."

	# we are in PATCHEDBRANCH here, make it DETACHED
	# so we can update the branch later...
	# (hoping git is inteligent enough to only change .git/HEAD)
	gitcmd checkout -q "$PATCHEDREV" || return 1
	HEADBRANCH=DETACHED

	debugout "Remove possible debian/ from upstream..."
	gitcmd rm --ignore-unmatch --cached -f -r -- debian || return 1
	debugout "To replace it with the one in verbatim import..."
	gitcmd read-tree --prefix=debian/ -i "${verbatimDEBIANREV}:debian" || return 1

	tree="$(gitcmd write-tree)" || return 1
	debianparents="-p $PATCHEDREV -p $verbatimDEBIANREV"
	if test -n "$oldDEBIANREV" && $not_yet_merged ; then
		debianparents="$debianparents -p $oldDEBIANREV"
		not_yet_merged=false
	fi
	commit="$(echo "Import $fsource $fversion" | gitcmd commit-tree $tree $debianparents)" || return 1
	gitcmd update-ref refs/heads/"$DEBIANBRANCH" "$commit" "$DEBIANREV" || return 1
	DEBIANREV="$commit"
	gitcmd checkout -f "$DEBIANBRANCH" || return 1
	HEADBRANCH="$DEBIANBRANCH"

	patched="$PATCHEDREV"
	gitcmd branch -d "$PATCHEDBRANCH" || return 1
	PATCHEDREV=""
}

function select_patch_system() {
	patch_system="$1"
	selected_patch_system="$1"
	case "$patch_system" in
		# aliases
		cdbs)
			patch_system=simple
			;;
		cdbs-first)
			patch_system=simple-first
			;;
		cdbs-applied)
			patch_system=simple-applied
			;;
		# supported
		auto|none|quilt|dpatch|history|simple|quilt-first|quilt-applied|dpatch-first|dpatch-applied|simple-first|simple-applied)
			;;
		# unsupported
		*)
			printerror "Unknown patch system '$patch_system'!"
			return 1
			;;
	esac
}

function do_import_dsc() {
	patch_author=""
	patch_fallbackauthor=""
	patch_date=""
	patch_edit=false
	connectoldupstream=true
	parents=""
	parent_commits=""
	branchname="HEAD"
	forcecommitreuse=false
	patch_system="auto"
	selected_patch_system=""
	imported_patches=false
	has_unmanaged_differences=false
	upstreamtouse=""
	verbatimbranchname=""

	while [ $# -gt 0 ] ; do
		case "$1" in
			--help)
				cat <<'EOF'
Syntax: git-dpm [global options] import-dsc <dsc-file>
Import a dsc file.
 --branch <name>: Use <name> instead what HEAD points to as
                  branch to create or update.
 -e, --edit-patches: add opportunity to edit patches imported
 -f, --force-reuse: use old commits for patches, even if the
                    description changed.
 --patch-system <mode>
   How to import patches found in a 1.0 format source package.
   auto: (default)
       try to determine directly
   none:
       don't try to find any patches (only the .diff gets applied)
   history:
       don't try to find any patches. But if the upstream tarball
       is the same, generate a new patch on top of the old changes.
       (Some as 'none' if there is no previous version.)
   quilt:
   	extract and apply debian/patches/series quilt-style patches
   dpatch:
   	extract and apply debian/patches/00list dpatch-style patches
	(only real patches are supported, not arbitrary scripts).
   simple:
   	extract and apply a cdbs simple-patchsys style debian/patches/
   (quilt|dpatch|simple)-first
        like quilt|dpatch|simple, but apply patches before applying .diff
   (quilt|dpatch|simple)-applied
   	like *-first, but assume patches are already applied in .diff
 --upstream-to-use <commit>: Assume the .orig.tar is already available
   as the named commit and use that instead of importing or reusing anything
   else. (Your responsibility to make sure it is equal enough to the file
   contents).
 --parent <commit>: if creating a new commit for the .orig.tar,
                    add this add parent node (can be repeated)
 --detached: if creating a new commit for the .orig.tar,
             do not make the old upstream a parent node
 --patch-author: force author of patches imported
 --patch-default-author: author for patches if none found
 --patch-context <number>: minimal lines of context to match (default: 1)
EOF
				return 0
				;;
			-e|--edit|--edit-patch|--edit-patches)
				patch_edit=true
				;;
			--patch-system)
				shift
				select_patch_system "$1" || return 1
				;;
			--patch-system=*)
				select_patch_system "${1#--patch-system=}" || return 1
				;;
			--verbatim|--verbatim-branch)
				shift
				verbatimbranchname="$1"
				;;
			--verbatim=*|--verbatim-branch=*)
				verbatimbranchname="${1#--verbatim=}"
				verbatimbranchname="${verbatimbranchname#--verbatim-branch=}"
				;;
			--patch-author|--author)
				shift
				patch_author="$1"
				;;
			--patch-author=*|--author=*)
				patch_author="${1#--patch-author=}"
				patch_author="${patch_author#--author=}"
				;;
			--patch-defaultauthor|--patch-default-author|--default-author|--defaultauthor)
				shift
				patch_fallbackauthor="$1"
				;;
			--patch-defaultauthor=*|--patch-default-author=*|--default-author=*|--defaultauthor=*)
				patch_fallbackauthor="${1#--patch-default-author=}"
				patch_fallbackauthor="${patch_fallbackauthor#--patch-defaultauthor=}"
				patch_fallbackauthor="${patch_fallbackauthor#--defaultauthor=}"
				patch_fallbackauthor="${patch_fallbackauthor#--default-author=}"
				;;
			--patch-context|-C)
				shift
				lines_must_match="$1"
				;;
			-C*|--patch-context=*)
				lines_must_match="${1#-C}"
				lines_must_match="${lines_must_match#--context=}"
				lines_must_match="${lines_must_match#--patch-context=}"
				;;
			--detached-upstream|--detached)
				connectoldupstream=false
				;;
			--upstream-to-use)
				shift
				upstreamtouse="$(gitcmd rev-parse --verify -q "$1" || true)"
				if test -z "$upstreamtouse" ; then
					printerror "'$1' is not known by git."
					return 1
				fi
				;;
			--upstream-to-use=*)
				upstreamtouse="$(gitcmd rev-parse --verify -q "${1#--upstream-to-use=}" || true)"
				if test -z "$upstreamtouse" ; then
					printerror "'${1#--upstream-to-use=}' is not known by git."
					return 1
				fi
				;;
			--parent|--upstream-parent)
				shift
				add_parent "$1" || return 1
				;;
			--parent=*|--upstream-parent=*)
				p=${1#--upstream-parent=}
				add_parent "${p#--parent=}" || return 1
				;;
			-f|--force-reuse|--force-commit-reuse)
				forcecommitreuse=true
				;;
			-b|--branch|--branch-name)
				shift
				branchname="$1"
				;;
			--branch=*|--branch-name=*)
				shift
				branchname="${1#--branch-name=}"
				branchname="${branchname#--branch=}"
				;;
			# Also available as global options
			--dpatch-allow-empty)
				dpatch_forbid_empty=false
				;;
			# usual stuff:
			--)
				shift
				break
				;;
			-*)
				printerror "Unrecognised import-dsc option '$1'!"
				return 1
				;;
			*)
				break
				;;
		esac
		shift
	done
	if test -n "$upstreamtouse" && test -n "$parents" ; then
		printerror "--upstream-to-use and --parent cannot be mixed!"
		return 1
	fi
	if test -n "$upstreamtouse" && ! $connectoldupstream ; then
		printwarn "--detached-upstream has no effect with --upstream-to-use!"
		return 1
	fi
	if [ $# -eq 0 ] ; then
		printerror "no dsc file given as argument"
		return 1
	fi
	dsc="$1"
	shift
	if [ $# -gt 0 ] ; then
		printerror "too many arguments"
		return 1
	fi

	checkgitdir
	cdtoplevel
	checkclean $allow_nonclean
	true > "$gitdir/dpm/oldcontrol"
	initbranchvariables "${branchname}" false

	oldDEBIANREV=""
	if test -n "$DEBIANREV" ; then
		oldDEBIANREV="$DEBIANREV"
		debugout "$DEBIANBRANCH exists. Assume update on top."
		parsedpmcontrolfile "" "keep-control"
		# we will do everything new and only using the old stuff
		# as parents. So no need to keep it in any branches,
		# thus removing it to avoid many ifs later...
		if test -n "$PATCHEDREV" ; then
			if [ "$PATCHEDREV" != "$control_patched" ; then
				printerror "branch $PATCHEDBRANCH exists and not up to date. Do something against this first (for example deleting it if you do not care for its contents)."
				return 1
			fi
			debugout "Removing old $PATCHEDBRANCH, to avoid problems later."
			gitcmd branch -D "$PATCHEDBRANCH"
			PATCHEDREV=""
		fi
		if test -n "$UPSTREAMREV" ; then
			if [ "$UPSTREAMREV" != "$control_patched" ; then
				printerror "branch $UPSTREAMBRANCH exists and not up to date. Do something against this first (for example deleting it if you do not care for its contents)."
				return 1
			fi
			debugout "Removing old $UPSTREAMBRANCH, to avoid problems later."
			gitcmd branch -D "$UPSTREAMBRANCH"
			UPSTREAMREV=""
		fi
	else
		debugout "no branch $DEBIANBRANCH, assuming creating new one"
		if test -n "$UPSTREAMREV" ; then
			printerror "$DEBIANBRANCH does not exists, but $UPSTREAMBRANCH does. import-dsc does not know that this means."
			return 1
		fi
		if test -n "$PATCHEDREV" ; then
			printerror "$DEBIANBRANCH does not exists, but $PATCHEDBRANCH does. import-dsc does not know that this means."
			return 1
		fi
		# set to NONE to make it easier to see if they are used uninitialized...
		control_upstream=NONE
		control_patches=NONE
		control_patched=NONE
		control_origtarname=NONE
		control_origtarsha=NONE
		control_origtarsize=NONE
	fi

	parse_dsc "$dsc"
	dirname="$(dirname "$dscfilename")"
	origname="${foundorigfilename:-$foundnativefilename}"
	basetar="$dirname/$origname"

	# look for an sha for the .orig.tar.gz in .dsc
	newsha="$(awk 'BEGIN { e2=ARGV[1] ; e3 = ARGV[1] ;
	   insha2 = 0 ; ARGV[1] = "" ; ARGV[2] = "" }
	   /^Checksums-Sha1:/ { insha2 = 1 ; next }
	   insha2 && ! /^ / { insha2 = 0 ; next }
	   insha2 && $2 == e2 && $3 == e3 { exit 1 } ' \
	   "$origsize" "$origname" "$dscfilename")"

	# Check if the .orig.tar is the same...
	if test -n "$upstreamtouse" ; then
		# we are told which branch to use, only make sure
		# we have an sha1 sum of the file:
		if test -z "$newsha" ; then
			if ! test -f "$basetar" ; then
				printerror "Cannot find $basetar"
				return 1
			fi
		fi
		tarsize="$(stat --printf '%s' "$basetar")"
		if [ "$tarsize" -ne "$origsize" ] ; then
			printerror "The $dscfilename says $basetar has size $origsize, but it has $tarsize"
			return 1
		fi
		origsha="$(sha1sum -b -- "$basetar")"
		origsha="${origsha%% *}"
	elif [ x"$origname" != x"$control_origtarname" ] || \
	   [ x"$origsize" != x"$control_origtarsize" ] || \
	   [ x"${newsha:-$control_origtarsha}" != x"$control_origtarsha" ] ; then
	   	debugout "New .orig.tar, will have to import it afresh"

		if ! test -f "$basetar" ; then
			printerror "Cannot find $basetar"
			return 1
		fi
		tarsize="$(stat --printf '%s' "$basetar")"
		if [ "$tarsize" -ne "$origsize" ] ; then
			printerror "The $dscfilename says $basetar has size $origsize, but it has $tarsize"
			return 1
		fi
		origsha="$(sha1sum -b -- "$basetar")"
		origsha="${origsha%% *}"
		reuse_upstream=false
	# if .dsc does not list it and we have the file, check it:
	elif test -z "$newsha" && test -f "$basetar" ; then
		tarsize="$(stat --printf '%s' "$basetar")"
		if [ "$tarsize" -ne "$origsize" ] ; then
			printerror "The $dscfilename says $basetar has size $origsize, but it has $tarsize"
			return 1
		fi
		origsha="$(sha1sum -b -- "$basetar")"
		origsha="${origsha%% *}"
		if [ x"$control_origtarsha" != x"$origsha" ] ; then
			printwarn "Last recorded $origname and new one have the same name and size, but different sha1 checksums!"
			reuse_upstream=false
		else
			reuse_upstream=true
		fi
	else
		reuse_upstream=true
		origsha="$control_origtarsha"
	fi

	oldverbatimcommit=""
	if test -n "$verbatimbranchname" ; then
		oldverbatimcommit="$(gitcmd rev-parse --verify -q "$verbatimbranchname" || true)"
	fi
	true > "$gitdir"/dpm/oldcommits
	if test -n "$upstreamtouse" ; then
		old_commit_count=0
		verbatimUPSTREAMREV="$upstreamtouse"
		gitcmd checkout -q "$verbatimUPSTREAMREV"
		HEADBRANCH=DETACHED
	elif $reuse_upstream ; then
		debugout "Reusing old upstreambranch ${control_upstream}, as $origname unchanged"
		verbatimUPSTREAMREV="$control_upstream"
		gitcmd checkout -q "$verbatimUPSTREAMREV"
		HEADBRANCH=DETACHED
		gitcmd rev-list --pretty="format:%H %T %P" --reverse "${control_upstream}..${control_patched}" | sed '/^commit/d' > "$gitdir/dpm/oldcommits"
		old_commit_count=$(wc -l "$gitdir/dpm/oldcommits")
		old_commit_count="${old_commit_count%% *}"
	else
		old_commit_count=0
		if test -n "$foundnativefilename" && test -n "$oldverbatimcommit" ; then
			parents="-p $oldverbatimcommit $parents"
			parent_commits="$oldverbatimcommit $parent_commits"
		elif $connectoldupstream && [ x"$control_upstream" != xNONE ] ; then
			parents="-p $control_upstream $parents"
			parent_commits="$control_upstream $parent_commits"
		fi
		debugout "Importing $basetar"
		import_tar "$basetar" "$parents" "$parent_commits" "Import ${origname}"
		verbatimUPSTREAMREV="$commit"
		# TODO: add flag to call pristine-tar commit here...
	fi
	if test -n "$DEBIANREV" && isancestor "$verbatimUPSTREAMREV" "$DEBIANREV" ; then
		# Allow more things where old commits can be recylced...
		gitcmd rev-list --pretty="format:%H %T %P" --reverse "${verbatimUPSTREAMREV}..${DEBIANREV}" | sed '/^commit/d' >> "$gitdir/dpm/oldcommits"
	fi
	if [ "$format" = "diff" ] && test -n "$oldverbatimcommit" && isancestor "$verbatimUPSTREAMREV" "$oldverbatimcommit" ; then
		# Those are most likely already in the DEBIANREV ones above,
		# but by adding them they get priority for the tail below
		gitcmd rev-list --pretty="format:%H %T %P" --reverse "${verbatimUPSTREAMREV}..${oldverbatimcommit}" | sed '/^commit/d' >> "$gitdir/dpm/oldcommits"
	fi

	not_yet_merged=true
	case $format in
		(diff)
			debugout "applying $founddifffilename (without debian/)..."
			# no -Cn, as .diff should always apply correctly...
			douncompress "$dirname/$founddifffilename" | \
			 gitcmd apply --index --whitespace=nowarn -p1 --exclude="debian/*" -
			prepatchedtree="$(gitcmd write-tree)"
			if [ "$prepatchedtree" != "$(gitcmd rev-parse "$verbatimUPSTREAMREV":)" ] ; then
				has_unmanaged_differences=true
				commit=""
				if $reuse_upstream && \
				   test -n "$control_patched" && \
				   [ x"$patch_system" = x"history" ] ; then
					if [ x"$prepatchedtree" = x"$(gitcmd rev-parse "${control_patched}:")" ] ; then
						debugout "Contents after .diff applied is the same as old patched branch, reuse that one"
						commit="$control_patched"
					else
						debugout "Adding additional commit on top of patched branch"
						commit="$(echo "Additional changes found in $founddifffilename" | gitcmd commit-tree "$prepatchedtree" -p "$control_patched")"
					fi
				else
					candidate="$(LC_ALL=C sed -n -e 's/^\([^ ]*\) '"$prepatchedtree"' '"$verbatimUPSTREAMREV"'$/\1/p' -- "$gitdir"/dpm/oldcommits | tail -n 1)"
					if test -n "$candidate" ; then
						# do not compare message here.
						# if that patch was here and gives
						# the right tree, it is better than
						# a "changes found in..."
						commit="$candidate"
						debugout "Reuse $commit for non-debian/ patches found in $founddifffilename"
					fi
				fi
				if test -n "$commit" ; then
					gitcmd checkout -q "$commit"
				else
					printwarn "$founddifffilename contains changes outside debian/, importing as single patch"
					# TODO: start editor to give better message?
					gitcmd commit -m "changes found in $founddifffilename"
				fi
			fi
			verbatimPATCHEDREV="$(gitcmd rev-parse HEAD)"
			debugout "change index and workdir back to unmodified upstream..."
			gitcmd checkout -q "$verbatimUPSTREAMREV"
			gitcmd reset --soft "$verbatimPATCHEDREV"
			debugout "apply diff, this time including debian/ ..."
			douncompress "$dirname/$founddifffilename" | \
			 gitcmd apply --index --whitespace=nowarn -p1 -
			if test -f debian/rules ; then
				chmod a+x debian/rules
				gitcmd update-index --add --replace debian/rules
			else
				printwarn "There does not seem to be a debian/rules file after applying $founddifffilename"
			fi
			tree="$(gitcmd write-tree)"
			addparents=""
			if test -n "$oldverbatimcommit" ; then
				addparents="-p $oldverbatimcommit"
			fi
			commit="$(echo "Import $(basename "$dscfilename")" | gitcmd commit-tree "$tree" -p "$verbatimPATCHEDREV" $addparents )"
			gitcmd checkout -q "$commit"
			verbatimDEBIANREV="$commit"
			;;
		(quilt)
			debugout "Importing $founddebianfilename"
			import_tar "$dirname/$founddebianfilename" "" "" "temporary commit containing .debian.tar file"
			debiantree="$(gitcmd rev-parse "$commit":)"
			debugout "changing back to upstream source"
			gitcmd checkout -q "$verbatimUPSTREAMREV"
			if gitcmd rev-parse --verify -q "${debiantree}:patches/series" >/dev/null ; then
				debugout "Importing patches"
				apply_patches "${debiantree}:" false
				imported_patches=true
			fi
			verbatimPATCHEDREV="$(gitcmd rev-parse --verify HEAD)"
			debugout "Remove possible debian/..."
			gitcmd rm --ignore-unmatch -f -r -- debian
			debugout "Replace debian/ with contents of .debian.tar."
			gitcmd read-tree --prefix=debian/ -i "$debiantree"
			gitcmd checkout-index -f -a
			debugout "Create the new debian branch commit"
			# where it the git commit with additional parent added...
			tree=$(gitcmd write-tree)
			if test -n "$verbatimbranchname" ; then
				addparents="-p $oldverbatimcommit"
				message="Import $(basename "$dscfilename")"
			elif test -n "$oldDEBIANREV" && $not_yet_merged ; then
				addparents="-p $oldDEBIANREV"
				not_yet_merged=false
				message="Import $fsource $fversion"
			else
				addparents=""
				message="Import $fsource $fversion"
			fi
			commit="$(echo "$message" | gitcmd commit-tree "$tree" -p HEAD $addparents)"
			verbatimDEBIANREV="$commit"
			gitcmd checkout -q "$commit"
			# 3.0 has built-in patch system, no more madness...
			patch_system=none3.0
			;;
		(oldnative|native)
			# no more things in the .dsc
			verbatimPATCHEDREV="$verbatimUPSTREAMREV"
			verbatimDEBIANREV="$verbatimUPSTREAMREV"
			;;
	esac
	if test -n "$verbatimbranchname" ; then
		gitcmd update-ref refs/heads/"$verbatimbranchname" "$verbatimDEBIANREV" "$oldverbatimcommit"
		echo "Updated $verbatimbranchname to contents of $dscfilename"
	fi
	debugout "import of verbatim content complete"
	case $format in
		(oldnative|native)
			printerror "1.0 without diff and 3.0 (native) cannot be imported"
			return 1
			;;
	esac

	upstream="$verbatimUPSTREAMREV"
	patched="$verbatimPATCHEDREV"
	gitcmd update-ref refs/heads/"$DEBIANBRANCH" "$verbatimDEBIANREV" "$oldDEBIANREV"
	DEBIANREV="$verbatimDEBIANREV"
	gitcmd checkout -q "$DEBIANBRANCH"
	HEADBRANCH="$DEBIANBRANCH"

	# TODO: does it make sense to create a partial .git-dpm here and
	# complete that once the patches finished? That might make it easier
	# if the user has to change anything to make that work...

	if [ "x$patch_system" = x"auto" ] ; then
		debugout "Trying to determine patch system in use..."
		# TODO: check for variables moving the patches to different places?
		if grep -q '^include[ 	]\+/usr/share/quilt/quilt.make' debian/rules ; then
			patch_system=quilt
		elif grep -q '^include[ 	]\+/usr/share/quilt/quilt.debbuild.mk' debian/rules ; then
			patch_system=quilt
		elif grep -q '^include[ 	]\+/usr/share/cdbs/1/rules/patchsys-quilt.mk' debian/rules ; then
			patch_system=quilt
		elif grep -q '^	dh\>.*--with quilt' debian/rules ; then
			patch_system=quilt
		elif grep -q '^include[ 	]\+/usr/share/dpatch/dpatch.make' debian/rules ; then
			patch_system=dpatch
		elif grep -q '^include[ 	]\+/usr/share/cdbs/1/rules/dpatch.mk' debian/rules ; then
			patch_system=dpatch
		elif grep -q '^include[ 	]\+/usr/share/cdbs/1/rules/simple-patchsys.mk' debian/rules ; then
			if grep -q 'DEB_PATCH_SUFFIX' debian/rules ; then
				printerror "debian/rules seems to change DEB_PATCH_SUFFIX. That is not supported by git-dpm. Imported patches will most likely be incomplete."
			fi
			if grep -q 'DEB_PATCHDIRS' debian/rules ; then
				printerror "debian/rules seems to change DEB_PATCHDIRS. That is not supported by git-dpm. Imported patches will most likely be incomplete."
			fi
			patch_system=simple
		elif test -f debian/patches/series ; then
			if test -n "$quilt_build_deps" ; then
				debugout "Has debian/patches series and build-depends on quilt, so assume they should be applied"
				patch_system="quilt"
			else
				debugout "Has debian/patches series, but no build-dependency on quilt, will try quilt-applied"
				patch_system="quilt-applied"
			fi
		else
			patch_system="nonefound"
		fi
	fi
	patch_system_="${patch_system%-first}"
	if [ x"$patch_system_" = x"$patch_system" ] ; then
		apply_patches_first=false
	else
		patch_system="$patch_system_"
		apply_patches_first=true
	fi
	patch_system_="${patch_system%-applied}"
	if [ x"$patch_system_" = x"$patch_system" ] ; then
		preapplied_patches=false
	else
		patch_system="$patch_system_"
		apply_patches_first=true
		preapplied_patches=true
	fi
	case "$patch_system" in
		none|none3.0|nonefound|history)
			;;
		quilt|dpatch|simple)
			# TODO: instead write some --continue/--abort logik...
			if ! import_patches_from_dsc ; then
				printerror "Could not import patches. (above this message should be some error messages from git indicating why)"
				echo "reseting branches to previous state." >&2
				echo "to debug what failed:" >&2
				echo "new upstream rev would have been ${verbatimUPSTREAMREV}" >&2
				echo "in .dsc patches ${verbatimPATCHEDREV}" >&2
				echo "in .dsc debian/ ${verbatimDEBIANREV}" >&2
				echo "applied patches got till $PATCHEDREV" >&2

				if test -n "$oldDEBIANREV" ; then
					debugout "resetting $DEBIANBRANCH to $oldDEBIANREV"
					gitcmd checkout -f -q "$oldDEBIANREV"
					gitcmd branch -D "$DEBIANBRANCH"
					gitcmd checkout -b "$DEBIANBRANCH"
					HEADBRANCH="$DEBIANBRANCH"
				elif [ "$ORIGHEADBRANCH" != "$DEBIANBRANCH" ] ; then
					debugout "removing $DEBIANBRANCH again..."
					gitcmd checkout -f "$ORIGHEADBRANCH"
					HEADBRANCH="$ORIGHEADBRANCH"
					gitcmd branch -D "$DEBIANBRANCH"
				else
					gitcmd checkout -q "$(gitcmd rev-parse HEAD)"
					HEADBRANCH=DETACHED
					gitcmd branch -D "$DEBIANBRANCH"
				fi
				if test -n "$verbatimbranchname" ; then
					if test -n "$oldverbatimcommit" ; then
						echo "reseting $verbatimbranchname from $verbatimDEBIANREV back to $oldverbatimcommit"
						gitcmd update-ref "refs/heads/$verbatimbranchname" "$oldverbatimcommit" "$verbatimDEBIANREV"
					else
						gitcmd branch -D "$verbatimbranchname"
					fi
				fi
				if test -n "$PATCHEDREV" ; then
					gitcmd branch -D "$PATCHEDBRANCH"
				fi
				return 1
			fi
			;;
		*)
			printerror "$patch_system patches not yet supported in import-dsc"
			return 1
			;;
	esac

	if test -n "$verbatimbranchname" && [ x"$DEBIANREV" = x"$verbatimDEBIANREV" ] ; then
		ammendopts=""
	else
		ammendopts="--amend"
	fi
	if test -n "$oldDEBIANREV" && $not_yet_merged ; then
		# TODO: how to get rid of the annoying "Automatic merge went well; stopped before committing as requested" message here?
		gitcmd merge --no-commit -s ours "$oldDEBIANREV" 2> /dev/null
		ammendopts=""
	fi

	debugout "Create debian/.git-dpm file..."
# TODO: improve this...
	cat > debian/.git-dpm <<EOF
# see git-dpm(1) from git-dpm package
${control_patches}
${patched}
${upstream}
${upstream}
${origname}
${origsha}
${origsize}
EOF
	control_patched="$patched"
	control_oldupstream="$upstream"
	control_upstream="$upstream"
	control_origtarname="$origname"
	control_origtarsha="$origsha"
	control_origtarsize="$origsize"
	tail -n +9 -- "$gitdir/dpm/oldcontrol" >> debian/.git-dpm
	gitcmd add debian/.git-dpm
	gitcmd commit $ammendopts -q -m "Import $fsource $fversion" -a
	if $delete_temp_files ; then
		rm -f -- "$gitdir/dpm/oldcontrol" "$gitdir/dpm/oldcommits"
	fi
	echo "$dscfilename successfully imported"
	case "$patch_system" in
		none|history)
			;;
		nonefound)
			if $has_unmanaged_differences ; then
				echo "Looks like no patch system was used but everything patched directly instead..."
			else
				echo "No patch system found. If there is one, you'll have to import the patches manually..."
			fi
			;;
		quilt-applied|none3.0)
			if $imported_patches ; then
				echo "To regenerate the patches, run git-dpm update-patches"
			fi
			;;
		*)
			if $imported_patches ; then
				echo "patches were imported and thus are now applied."
				if ! $preapplied_patches ; then
					echo "You will most likely have to change the build-system"
					echo "to no longer apply them at build time."
				fi
				echo "To export the patches as debian/patches quilt series,"
				echo "use git-dpm update-patches."
			fi
			;;
	esac
}


########## cherry-pick ############

function do_cherry_pick() {
	merge_only=false
	disallow_nonlinear=true
	amendmerge=false
	delete_patched=true
	pass_options=""
	redo=false
	merge_parent=""
	while [ $# -gt 0 ] ; do
		case "$1" in
			--help)
				cat <<'EOF'
Syntax: git-dpm [global options] cherry-pick [-e] [-s] [-x|-r] [-m parent] <commit>
 Cherry-pick a commit into the patched branch.
 This is mostly a safer/faster form of
  git-dpm checkout-patch ; git cherry-pick ; git-dpm update-patches
Possible local options:
 --merge-only: Do not update debian/patches
 --repick: don't try to avoid applying something already contained
 --allow-nonlinear: passed to git-dpm merge-patched-into-debian
 --keep-branch: dont' remove the patched temporary branch when done.
 --amend: passed to git-dpm merge-patched-into-debian
 -e, -s, -x, -m num: passed along to git's cherry-pick
EOF
				return 0
				;;
			--merge-only)
				merge_only=true
				;;
			# git's checky-pick options:
			-e|--edit|-s|--signoff|-x|-r)
				pass_options="$pass_options $1"
				;;
			-m|--mainline)
				shift
				merge_parent="$1"
				pass_options="$pass_options -m $merge_parent"
				;;
			--mainline=*)
				merge_parent="${1#--mainline=}"
				pass_options="$pass_options -m $merge_parent"
				;;
			--repick)
				redo=true
				;;
			# merge-patched-into-debian options:
			--allow-nonlinear)
				disallow_nonlinear=false
				;;
			--keep-branch)
				delete_patched=false
				;;
			--amend)
				amendmerge=true
				;;
			# usual stuff:
			--)
				shift
				break
				;;
			-*)
				printerror "Unrecognised import-new-upstream option '$1'!"
				return 1
				;;
			*)
				break
				;;
		esac
		shift
	done
	if [ $# -eq 0 ] ; then
		printerror "no commit given as argument"
		return 1
	fi
	committopick="$1"
	shift
	if [ $# -gt 0 ] ; then
		printerror "too many arguments"
		return 1
	fi
	checkgitdir
	initbranchvariables
	cdtoplevel
	checkclean $allow_nonclean
	parsedpmcontrolfile ""
	checkupstreambranchcurrent

	checkdebian

	TOPICKREV="$(gitcmd rev-parse --verify "$committopick" || true)"
	if test -z "$TOPICKREV" ; then
		printerror "Unable to identify commit '$committopick'!"
		return 1
	fi

	if test -n "$PATCHEDREV" && [ "$PATCHEDREV" != "$control_patched" ] ; then
		printerror "you already have '$PATCHEDBRANCH' branch different from the last recorded"
		echo "Either remove that or use git's cherry-pick instead followed by a git-dpm update-patches" >&2
		return 1
	fi

	debugout "checking if '$committopick' ('$TOPICKREV') is sane..."
	if isancestor "$TOPICKREV" "$control_patched" ; then
		if $redo ; then
			printwarn "trying to repick..."
		else
			printerror "'$committopick' is already included in '$PATCHEDBRANCH'"
			echo "To force processing use --repick" >&2
			return 1
		fi
	elif isancestor "$TOPICKREV" "$DEBIANREV" ; then
		printerror "'$committopick' is part of '$DEBIANBRANCH' but not '$PATCHEDBRANCH'."
		echo "Use git-dpm isolate-changes for this case."
		return 1
	fi

	debugout "Check if commit is a merge and if yes if -m was correctly given"
	numparentsplusone="$(gitcmd rev-list --max-count=1 --parents "$TOPICKREV" | wc -w)"
	if test -z "$merge_parent" ; then
		if [ 2 -eq "$numparentsplusone" ] ; then
			comparewith="$TOPICKREV"'^1'
		else
			printerror "'$committopick' is a merge. Perhaps you need --mainline parent_num?"
			return 1
		fi
	else
		if [ 0 -lt "$merge_parent" ] && [ "$numparentsplusone" -gt "$merge_parent" ] ; then
			comparewith="$(gitcmd --verify "$TOPICKREV"'^'"$merge_parent")"
		else
			printerror "'$merge_parent' not in interval 1..$(( "$merge_parent" - 1 ))!"
			return 1
		fi
	fi
	debugout "Check if commit has changes in debian/"
	badrevs="$(gitcmd rev-list "${comparewith}..${TOPICKREV}" -- ${reldir}debian/)"
	if [ -n "$badrevs" ] ; then
		printerror "'$committopick' contains debian/ changes:"
		gitcmd rev-list --pretty=oneline "${comparewith}..${TOPICKREV}" -- ${reldir}debian/ >&2
		return 1
	fi

	if test -n "$PATCHEDREV" ; then
		debugout "Switching to '$PATCHEDBRANCH'"
		[ "$PATCHEDREV" == "$control_patched" ] || printerror "CONFUSED"
		gitcmd checkout "$PATCHEDBRANCH"
	else
		debugout "Creating '$PATCHEDBRANCH'"
		gitcmd checkout -b "$PATCHEDBRANCH" "$control_patched"
		PATCHEDREV="$control_patched"
	fi
	HEADBRANCH="$PATCHEDBRANCH"
	r=0
	gitcmd cherry-pick $pass_options -- "$committopick" || r=$?
	if [ "$r" -ne 0 ] ; then
		printerror "git cherry-pick failed. Try to repair and then run git-dpm update-patches."
		return 1
	fi
	newPATCHEDREV="$(gitcmd rev-parse --verify HEAD)"
	if [ x"$newPATCHEDREV" = x"$PATCHEDREV" ] ; then
		printwarn "git's cherry-pick did not change '$PATCHEDBRANCH', doing nothing..."
		if [ x"$ORIGHEADBRANCH" != x"$PATCHEDBRANCH" ] && $delete_patched ; then
			gitcmd checkout "$ORIGHEADBRANCH"
			HEADBRANCH="$ORIGHEADBRANCH"
			gitcmd branch -D "$PATCHEDBRANCH"
		fi
		return 0
	fi
	PATCHEDREV="$newPATCHEDREV"

	debugout "switching to '$DEBIANBRANCH'"
	gitcmd checkout "$DEBIANBRANCH"
	HEADBRANCH="$DEBIANBRANCH"

	echo "git-dpm: Calling merge-patched-into-debian..."
	# TODO: check earlier if there are any changes in debian that will get lost?
	commitmessage="cherry-picked '$(gitcmd rev-list --max-count=1 --abbrev=8 --abbrev-commit --pretty=oneline "$committopick")' into '$PATCHEDBRANCH'"
	merge_patched_in_debian true "$disallow_nonlinear" "$amendmerge"
	# needed by update_patches
	patchedrev="$control_patched"
	if $delete_patched ; then
		gitcmd branch -d "$PATCHEDBRANCH"
	fi
	# needed by update_patches
	amendifneeded="--amend"
	if $merge_only ; then
		printwarn "Don't forget to run update-patches..."
		return 0
	fi
	echo "git-dpm: Calling update-patches..."
	update_patches
	return 0
}

############ MAIN ###############

case "$1" in
	version)
		echo "git-dpm version $VERSION"
		exit 0
		;;
	init)
		shift
		do_init "$@"
		;;
	status)
		shift
		do_status "$@"
		;;
	update-patches|up|u-p|ci)
		shift
		do_update_patches "$@"
		;;
	merge-patched|merge-patched-into-debian)
		shift
		do_merge_patched_into_debian "$@"
		;;
	prepare|prep)
		shift
		do_prepare "$@"
		;;
	checkout-patched|co|c-p)
		shift
		do_checkout_patched "$@"
		;;
	linearize)
		shift
		do_linearize "$@"
		;;
	rebase-patched|r-p)
		shift
		do_rebase_patched "$@"
		;;
	new-upstream-branch|new-upstream|n-u)
		shift
		do_new_upstream_branch "$@"
		;;
	tag)
		shift
		do_tag "$@"
		;;
	apply-patch|a-p)
		shift
		do_apply_patch "$@"
		;;
	import-tar|i-t)
		shift
		do_import_tar "$@"
		;;
	import-dsc)
		shift
		do_import_dsc "$@"
		;;
	import-new-upstream|i-n-u|inu)
		shift
		do_import_new_upstream "$@"
		;;
	cherry-pick|c-p)
		shift
		do_cherry_pick "$@"
		;;
	*)
		printerror "Unrecognised command '$1'!"
		exit 1
		;;
esac
if ! $dosilent ; then
	case "$HEADBRANCH" in
		""|"$ORIGHEADBRANCH"|DETACHED)
			;;
		*)
	       		echo "You are now in branch '$HEADBRANCH'"
			;;
	esac
fi
exit 0
