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 <[EMAIL PROTECTED]>
#
# 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 via email to