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.
signature.asc
Description: Digital signature

