[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: "dpkg-git update" and "dpkg-git commit"



On Sun, 28 Oct 2007, Helge Kreutzmann wrote:
> > We have no way to filter anything on the server side. But maybe we can
> > provide you some scripts that hide the git commands behind two scripts
> > like "dpkg-git update" and "dpkg-git commit" (which would have the
> > same logic as SVN).
> I like the idea quite a bit and thus would be enlightend if something
> like this could be implemented and distributed. This would also allow
> you to update the actual git commands without anyone noticing :-))

I had a try to create such a command. It's attached to this mail. It
requires git 1.5.3 as "git-stash" is used.

It tries to mimic the behaviour of svn. Put the script in your dpkg
repository and call it from the root of the repository.

There are two important commands only:
./dpkg-vcs update
./dpkg-vcs commit

The output of the script itself is prefixed with "**" so that you can
easily skip git's own output (in case you don't understand it). The
script does a fair number of verifications and checks the exit code of
several important git command and gives you proper indication on how
to continue.

Please try it and feel free to give some feedback.

Cheers,
-- 
Raphaël Hertzog

Premier livre français sur Debian GNU/Linux :
http://www.ouaza.com/livre/admin-debian/
#!/bin/sh

# Copyright 2007 Raphael Hertzog <hertzog@debian.org>
#
# This program is free software; you may redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This 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.
#
# A copy of the GNU General Public License is available as
# /usr/share/common-licenses/GPL in the Debian GNU/Linux distribution
# or on the World Wide Web at http://www.gnu.org/copyleft/gpl.html.
# You can also obtain it by writing to the Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

# This script is only meant to be used in the master branch of dpkg
# This branch is created by default by a git clone
# ssh://git.debian.org/git/dpkg/dpkg.git

# Git 1.5.3 is required (for git-stash)

has_changes_in_index() {
    # git-diff --quiet returns 1 when there are changes
    if git diff --quiet --cached; then
	return 1
    else
	return 0
    fi
}
has_changes_in_working_tree() {
    # git-diff --quiet returns 1 when there are changes
    if git diff --quiet; then
	return 1
    else
	return 0
    fi
}
is_uptodate() {
    unmerged=`git rev-list origin/master ^HEAD`
    if test -z "$unmerged"; then
	return 0
    else
	return 1
    fi
}
has_unpushed_commits() {
    unpushed=`git rev-list HEAD ^origin/master`
    if test -n "$unpushed"; then
	return 0
    else
	return 1
    fi
}

test -d .git || {
    echo "This script must be called from the root of dpkg's git repository." >&2
    exit
}
branch=`git-name-rev --name-only HEAD`
[ "$branch" = "master" ] || {
    echo "This script must be called from dpkg's master branch." >&2
    echo "Call 'git checkout master'."
    exit
}

case $1 in
    update)
	git fetch --quiet origin

	if has_unpushed_commits; then
	    echo "** You have local commits that were not pushed to the remote repository."
	    if is_uptodate; then
		echo "** They are still OK to be pushed."
	    else
		echo "** The remote repository has evolved. Rebasing your work."
		$0 rebase
	    fi
	else
	    if ! is_uptodate; then
		echo "** The remote repository has changed. Trying to update."
		if has_changes_in_index || has_changes_in_working_tree; then
		    git merge origin/master
		    result=$?
		    if [ $result -eq 0 ]; then
			echo "** The repository has been updated."
		    elif [ $result -eq 1 ]; then
			echo "** The repository has been updated but there have been conflicts:"
			git ls-files --unmerged | awk '{print $4}' | uniq -c
		    else
			echo "** The automatic merge failed. Try another stratrgy."
			echo "** Pushing local changes aside with git stash"
			git stash save "WIP saved by dpkg-vcs"
			echo "** Merging remote changes, should result in fast-forward"
			git merge origin/master
			echo "** Reapplying local changes with git stash apply"
			git stash apply
			result=$?
			if [ $result -eq 0 ]; then
			    echo "** Local changes have been merged"
			elif [ $result -eq 1 ]; then
			    echo "** Local changes have been merged but there have been conflicts:"
			    git ls-files --unmerged | awk '{print $4}' | uniq -c
			else
			    echo "** git stash apply failed badly and returned $result."
			    echo "** You're on your own..."
			    exit 2
			fi
		    fi
		fi
	    else
		echo "** Nothing updated, the remote respository hasn't changed."
	    fi
	fi

    ;;
    commit)
	git fetch --quiet origin

	if ! is_uptodate; then
	    echo "** You're not up-to-date, please do '$0 update' first."
	    exit 1
	fi

	if has_changes_in_index || has_changes_in_working_tree; then
	    echo "** Committing changes locally"
	    git commit -a || {
		echo "** git commit failed, stopping here."
		exit 1
	    }
	fi

	if has_unpushed_commits; then
	    echo "** Pushing your changes to the remote repository"
	    echo "Here's a resume of what you're going to push:"
	    git rev-list --pretty=oneline --abbrev-commit master ^origin/master
	    echo "** Do you confirm that you want to push? [Yn] "
	    read answer
	    if [ "$answer" = "" ] || [ "$answer" = "y" ] || [ "$answer" = "Y" ]; then
		echo "** Calling 'git push'"
		git push
	    fi
	fi

    ;;
    rebase)
	git fetch --quiet origin

	if [ -z "$2" ]; then
	    echo "** Starting a rebase process..."
	    git rebase origin/master
	    result=$?
	else
	    if [ "$2" = "--continue" ] || [ "$2" = "--skip" ]; then
		if [ "$2" = "--continue" ]; then
		    for file in `git ls-files --unmerged | awk '{print $4}' | uniq`; do
		        git add $file
		    done
		fi
		git rebase $2
		result=$?
	    else
		echo "Invalid option for '$0 rebase': $2" >&2
		exit 1
	    fi
	fi

	if [ $result -eq 0 ]; then
	    echo "** The rebase process is finished. Your repository is up-to-date."
	    exit 0
	elif [ $result -eq 1 ]; then
	    echo "** Rebase process interrupted by conflicts."
	    echo "** Edit the files below and fix all the conflicts,"
	    echo "** then call '$0 rebase --continue':"
	    git ls-files --unmerged | awk '{print $4}' | uniq -c
	    exit 1
	else
	    echo "** The rebase process miserably failed for an unknown reason."
	    echo "** Aborting it."
	    git rebase --abort
	    exit 2
	fi
    ;;
    *)
    echo "$0: invalid syntax" >&2
    echo "$0 update: update the master branch of the repository" >&2
    echo "$0 commit: commit and push the changes to the master repository" >&2
    ;;
esac

Reply to: