On Wed, Nov 19, 2008 at 05:48:06PM +0100, Guido Guenther wrote:
> severity 506211 wishlist
> thanks
> 
> Roger Leigh schrieb:
> > The import fails with merge failure.  While it is true that there are
> > conflicts in the merge, we already have the means to resolve it: the
> > result of the merge is the orig.tar.gz with the .diff.gz applied--
> > the maintainer has already resolved the conflicts for us, so it shouldn't
> > be too difficult to fix up the failure and continue.
> This could be made an extra option (like --no-merge), patches would be
> welcome.

I finally figured out how to do this, and it will fix a number of other
serious bugs in git-buildpackage's importing of sources.

The problem is that your implementation is doing the importing the
hard and fragile way, using the git porcelain, when it could so it
in a far simpler and more reliable manner using the git core
plumbing.

As an example, take what's currently done to import an orig source
(approximately)

- check if working tree is dirty
- switch to orig branch
- unpack source
- remove and add files to make the working tree match the branch
- commit
- checkout master branch
- merge

I've seen random bits in the tree get comitted using git-import-*
e.g. if in .gitignore or otherwise not noticed.
There's a far far simpler way:

- unpack source
- add sources into an alternate index
- git write-tree to write index into repo
- git commit-tree to commit
- git update-ref to update the orig branch

At no point is the working tree touched.

This handles easy merging, because the merge occurs at the git
commit-tree point.  You specify the parent(s) of the commit.
For the orig/upstream branch, that's just a single parent,
but for the debian branch, the parents will be the old debian
version and the upstream version for that version.  No
need to resolve conficts /because they were already resolved/.


I've been adding git "make dist" support to automake, which is how
I discovered how this works.  The script is attached below to
show how it works.  It's a make rule in shell script, but it
should show how to do this.  Simplified, it's just a few lines:

git show-ref --tags -q $tag [check tag exists or not]
GIT_INDEX_FILE="$INDEX" GIT_WORK_TREE="$UNPACKED_TREE" git add -A [add files]
  - no need to remove any files here; we create the index with a single command
GIT_INDEX_FILE="$INDEX" TREE="$(git write-tree)" [write out tree into git]
  TREE=SHA hash of tree
COMMIT="$(echo "$COMMIT_MESSAGE" | git commit-tree "$TREE" $COMMIT_OPTS)"
  [commit tree into git]
  COMMIT=SHA hash of commit
  COMMIT_OPTS = -p PARENT1 [ -p PARENT2 ] ... [ -p PARENTn ]
git update-ref "refs/heads/$branchname" "$COMMIT" "$current_commit"
  [update git branch head]
Then tag the commit.


If you replace the current way of switching branches and doing commits
with this method, git-import-* will become much more robust and reliable,
and it will fix the merge bug at the same time, so you'll get a proper
tracable history with all of the mergepoints in it.


Regards,
Roger


This is my full script:

GIT_RELEASE_BRANCH=HEAD
GIT_RELEASE_TAG=true
GIT_RELEASE_TAG_SIGN=true
GIT_RELEASE_TAG_NAME=release/$(PACKAGE)-$(VERSION)
GIT_RELEASE_TAG_MESSAGE="Release of $(PACKAGE)-$(VERSION)"

GIT_DIST_BRANCH=distrib
GIT_DIST_COMMIT_MESSAGE="Distribution of $(PACKAGE) version $(VERSION)"
GIT_DIST_TAG=true
GIT_DIST_TAG_SIGN=true
GIT_DIST_TAG_NAME=distribution/$(PACKAGE)-$(VERSION)
GIT_DIST_TAG_MESSAGE="Distribution of $(PACKAGE)-$(VERSION)"

dist-git: distdir
        cd "$(abs_top_srcdir)"; \
        if [ ! -d .git ]; then \
            echo "dist-git: Not a git repository" 1>&2; \
            exit 1; \
        fi; \
        if [ "$(GIT_RELEASE_TAG)" = "true" ]; then \
          if git show-ref --tags -q $(GIT_RELEASE_TAG_NAME); then \
            echo "git release tag $(GIT_RELEASE_TAG_NAME) already exists; not 
distributing" 1>&2; \
            exit 1; \
          fi; \
        fi; \
        if [ "$(GIT_DIST_TAG)" = "true" ]; then \
          if git show-ref --tags -q $(GIT_DIST_TAG_NAME); then \
            echo "git distribution tag $(GIT_DIST_TAG_NAME) already exists; not 
distributing" 1>&2; \
            exit 1; \
          fi; \
        fi; \
        DISTDIR_INDEX="$(abs_top_builddir)/$(distdir).git.idx"; \
        DISTDIR_TREE="$(abs_top_builddir)/$(distdir)"; \
        rm -f "$$DISTDIR_INDEX"; \
        GIT_INDEX_FILE="$$DISTDIR_INDEX" GIT_WORK_TREE="$$DISTDIR_TREE" git add 
-A || exit 1; \
        GIT_INDEX_FILE="$$DISTDIR_INDEX" TREE="$$(git write-tree)"; \
        rm -f "$$DISTDIR_INDEX"; \
        [ -n "$$TREE" ] || exit 1; \
        RELEASE_HEAD="$$(git show-ref -s $(GIT_RELEASE_BRANCH))"; \
        COMMIT_OPTS="-p $$RELEASE_HEAD"; \
        DIST_PARENT="$$(git show-ref --heads -s 
refs/heads/$(GIT_DIST_BRANCH))"; \
        if [ -n "$$DIST_PARENT" ]; then \
          COMMIT_OPTS="$$COMMIT_OPTS -p $$DIST_PARENT"; \
        fi; \
        COMMIT="$$(echo $(GIT_DIST_COMMIT_MESSAGE) | git commit-tree "$$TREE" 
$$COMMIT_OPTS)"; \
        [ -n "$$COMMIT" ] || exit 1; \
        git update-ref "refs/heads/$(GIT_DIST_BRANCH)" "$$COMMIT" 
"$$DIST_PARENT" || exit 1;\
        if [ "$(GIT_RELEASE_TAG)" = "true" ]; then \
          RELEASE_TAG_OPTS=""; \
          if [ "$(GIT_RELEASE_TAG_SIGN)" = "true" ]; then \
            RELEASE_TAG_OPTS="$$TAG_OPTS -s"; \
          fi; \
          git tag -m $(GIT_RELEASE_TAG_MESSAGE) $$RELEASE_TAG_OPTS 
"$(GIT_RELEASE_TAG_NAME)" "$$COMMIT" || exit 1; \
            echo "release tagged as $(GIT_RELEASE_TAG_NAME)"; \
        fi; \
        if [ "$(GIT_DIST_TAG)" = "true" ]; then \
          DIST_TAG_OPTS=""; \
          if [ "$(GIT_DIST_TAG_SIGN)" = "true" ]; then \
            DIST_TAG_OPTS="$$TAG_OPTS -s"; \
          fi; \
          git tag -m $(GIT_DIST_TAG_MESSAGE) $$DIST_TAG_OPTS 
"$(GIT_DIST_TAG_NAME)" "$$COMMIT" || exit 1; \
            echo "distribution tagged as $(GIT_DIST_TAG_NAME)"; \
        fi;
        $(am__remove_distdir)

-- 
  .''`.  Roger Leigh
 : :' :  Debian GNU/Linux             http://people.debian.org/~rleigh/
 `. `'   Printing on GNU/Linux?       http://gutenprint.sourceforge.net/
   `-    GPG Public Key: 0x25BFB848   Please GPG sign your mail.

Attachment: signature.asc
Description: Digital signature

Reply via email to