git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [JGIT] help needed to create a siimple commit
@ 2009-02-03 11:07 Yann Simon
  2009-02-03 15:51 ` Shawn O. Pearce
  0 siblings, 1 reply; 4+ messages in thread
From: Yann Simon @ 2009-02-03 11:07 UTC (permalink / raw)
  To: Shawn O. Pearce, Robin Rosenberg; +Cc: git

Hi,

I wrote the following unit test to learn how to make a commit with JGIT:

package org.spearce.jgit.lib;

import java.io.File;
import java.io.IOException;

public class CommitTest extends RepositoryTestCase {

	public void testASimpleCommit() throws IOException {
		
		GitIndex index = new GitIndex(db);
		index.filemode = Boolean.TRUE;
		
		File file;
		file = writeTrashFile("file1", "file1");
		
		index.add(trash, file);
		index.write();
		ObjectId objectId = index.writeTree();
		Tree tree = db.mapTree(objectId);
		tree.accept(new WriteTree(trash, db), TreeEntry.MODIFIED_ONLY);
		
		final Commit c1 = new Commit(db);
		c1.setAuthor(new PersonIdent(jauthor, 1154236443000L, -4 * 60));
		c1.setCommitter(new PersonIdent(jcommitter, 1154236443000L, -4 * 60));
		c1.setMessage("A Commit\n");
		c1.setTree(tree);
		assertEquals(tree.getTreeId(), c1.getTreeId());
		c1.commit();
		
	}
}

But the result is not brillant.
In the trash workspace, git log does not show me my commit.
git diff --cached shows me that my file is in the index but not committed...

Thank for the help.

Yann

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [JGIT] help needed to create a siimple commit
  2009-02-03 11:07 [JGIT] help needed to create a siimple commit Yann Simon
@ 2009-02-03 15:51 ` Shawn O. Pearce
  2009-02-04 16:10   ` Yann Simon
  0 siblings, 1 reply; 4+ messages in thread
From: Shawn O. Pearce @ 2009-02-03 15:51 UTC (permalink / raw)
  To: Yann Simon; +Cc: Robin Rosenberg, git

Yann Simon <yann.simon.fr@gmail.com> wrote:
> I wrote the following unit test to learn how to make a commit
> with JGIT:
> 
> 	public void testASimpleCommit() throws IOException {
> 		
> 		GitIndex index = new GitIndex(db);
> 		index.filemode = Boolean.TRUE;
> 		
> 		File file;
> 		file = writeTrashFile("file1", "file1");
> 		
> 		index.add(trash, file);
> 		index.write();
> 		ObjectId objectId = index.writeTree();
> 		Tree tree = db.mapTree(objectId);
> 		tree.accept(new WriteTree(trash, db), TreeEntry.MODIFIED_ONLY);
> 		
> 		final Commit c1 = new Commit(db);
> 		c1.setAuthor(new PersonIdent(jauthor, 1154236443000L, -4 * 60));
> 		c1.setCommitter(new PersonIdent(jcommitter, 1154236443000L, -4 * 60));
> 		c1.setMessage("A Commit\n");
> 		c1.setTree(tree);
> 		assertEquals(tree.getTreeId(), c1.getTreeId());
> 		c1.commit();

You are missing the final step of updating the HEAD ref with the
commit.  Calling commit() on the Commit object only writes it to
the object database, this is similar to git-commit-tree.

Try adding on the end:

	RefUpdate ru = db.updateRef(Constants.HEAD);
	ru.setRefLogMessage("commit");
	ru.setNewObjectId(c1.getCommitId());
	assertSame(RefUpdate.Result.NEW, ru.update());

If your commit had parents, you might want to do instead:

	ru.setExpectedOldObjectId(oldHEAD);
	assertSame(RefUpdate.Result.FAST_FORWARD, ru.update());

where oldHEAD is the value of HEAD you read and used as the first
parent of the commit.  This ensures that the update method fails
if someone else has updated HEAD since you last read it.

The update method returns a number of different states, usually we
check its result with a switch statement as a number of states are
sometimes permissible in a context.  Sometimes though, you know it
has to be exactly one state, and everything else is a failure.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [JGIT] help needed to create a siimple commit
  2009-02-03 15:51 ` Shawn O. Pearce
@ 2009-02-04 16:10   ` Yann Simon
  2009-02-04 17:07     ` Shawn O. Pearce
  0 siblings, 1 reply; 4+ messages in thread
From: Yann Simon @ 2009-02-04 16:10 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Robin Rosenberg, git

2009/2/3 Shawn O. Pearce <spearce@spearce.org>:
> You are missing the final step of updating the HEAD ref with the
> commit.  Calling commit() on the Commit object only writes it to
> the object database, this is similar to git-commit-tree.
>
> Try adding on the end:
>
>        RefUpdate ru = db.updateRef(Constants.HEAD);
>        ru.setRefLogMessage("commit");
>        ru.setNewObjectId(c1.getCommitId());
>        assertSame(RefUpdate.Result.NEW, ru.update());
>
> If your commit had parents, you might want to do instead:
>
>        ru.setExpectedOldObjectId(oldHEAD);
>        assertSame(RefUpdate.Result.FAST_FORWARD, ru.update());
>
> where oldHEAD is the value of HEAD you read and used as the first
> parent of the commit.  This ensures that the update method fails
> if someone else has updated HEAD since you last read it.
>
> The update method returns a number of different states, usually we
> check its result with a switch statement as a number of states are
> sometimes permissible in a context.  Sometimes though, you know it
> has to be exactly one state, and everything else is a failure.
>
I updated my simple test like this:

package org.spearce.jgit.lib;

import java.io.File;
import java.io.IOException;

public class CommitTest extends RepositoryTestCase {

	public void testASimpleCommit() throws IOException {
		
		recursiveDelete(trash_git, false, null, true);
		db = new Repository(trash_git);
		db.create();

		GitIndex index = new GitIndex(db);
		index.filemode = Boolean.TRUE;
		
		commitIndex(index, "commit 1");

		File file1 = writeTrashFile("file1", "file1");
		index.add(trash, file1);
		
		commitIndex(index, "commit 2");

	}
	
	private void commitIndex(GitIndex index, String commitMessage) throws
IOException {
		index.write();
		ObjectId objectId = index.writeTree();
		Tree tree = db.mapTree(objectId);
		final Commit commit = new Commit(db);
		commit.setAuthor(new PersonIdent(jauthor, 1154236443000L, -4 * 60));
		commit.setCommitter(new PersonIdent(jcommitter, 1154236443000L, -4 * 60));
		commit.setMessage(commitMessage);
		commit.setTree(tree);
		assertEquals(tree.getTreeId(), commit.getTreeId());
		commit.commit();
		
		ObjectWriter writer = new ObjectWriter(db);
		commit.setCommitId(writer.writeCommit(commit));

		Ref oldHEAD = db.getAllRefs().get(Constants.HEAD);
		final RefUpdate ru = db.updateRef(Constants.HEAD);
		ru.setNewObjectId(commit.getCommitId());
		ru.setRefLogMessage(commitMessage, false);

		if (oldHEAD != null) {
			// commit has parents
			ru.setExpectedOldObjectId(oldHEAD.getObjectId());
			assertSame(RefUpdate.Result.FAST_FORWARD, ru.update());
		} else {
			// commit has no parents
			assertSame(RefUpdate.Result.NEW, ru.update());
		}
		

	}
}

The first commit "with an empty workspace" is ok. I can see the commit
in the log.
The second commit fails, with ru.update() = REJECTED.

I tried different combination, without success.

If someone could tell me, what I am doing wrong...

Yann

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [JGIT] help needed to create a siimple commit
  2009-02-04 16:10   ` Yann Simon
@ 2009-02-04 17:07     ` Shawn O. Pearce
  0 siblings, 0 replies; 4+ messages in thread
From: Shawn O. Pearce @ 2009-02-04 17:07 UTC (permalink / raw)
  To: Yann Simon; +Cc: Robin Rosenberg, git

Yann Simon <yann.simon.fr@gmail.com> wrote:
> 		final Commit commit = new Commit(db);
> 		commit.setAuthor(new PersonIdent(jauthor, 1154236443000L, -4 * 60));
> 		commit.setCommitter(new PersonIdent(jcommitter, 1154236443000L, -4 * 60));
> 		commit.setMessage(commitMessage);
> 		commit.setTree(tree);

FWIW, its faster to use setTreeId().  Then you don't need to use
mapTree to read the tree object into memory.  This is an older area
of the Commit class API, before we understood how important it was
to avoid processing unnecessary data.  :-)

> 		assertEquals(tree.getTreeId(), commit.getTreeId());
> 		commit.commit();
> 		
> 		ObjectWriter writer = new ObjectWriter(db);
> 		commit.setCommitId(writer.writeCommit(commit));

Uh, commit.commit() is doing the same work as the above two lines,
so these above two lines are a no-op as the object already exists
in the object database.
 
> 		Ref oldHEAD = db.getAllRefs().get(Constants.HEAD);
> 		final RefUpdate ru = db.updateRef(Constants.HEAD);
> 		ru.setNewObjectId(commit.getCommitId());
> 		ru.setRefLogMessage(commitMessage, false);
> 
> 		if (oldHEAD != null) {
> 			// commit has parents
> 			ru.setExpectedOldObjectId(oldHEAD.getObjectId());
> 			assertSame(RefUpdate.Result.FAST_FORWARD, ru.update());

This fails because the commit has no parents, but you asked
for a fast-forward update.  Since HEAD already has a commit,
and the new commit isn't a super-set of the existing HEAD, and
RefUpdate.isForceUpdate() is false, the update is being rejected.

If you really mean to replace the commit, e.g. commit --amend,
you need to ru.setForceUpdate(true).

If you really mean to fast-forward the commit, e.g. just make
a new commit on top of the existing commits, you need to do
the read to get oldHEAD *before* you call commit.commit()
above, and use:

  commit.setParents(new Object[]{ oldHEAD.getObjectId() })

to set the current commit as the first parent of the new commit,
so the new commit is really a superset of the old one.

Again, back to the basic DAG in Git... JGit is just a library with
the building blocks necessary to manipulate the DAG.  Its up to
the appliction to create the new nodes correctly for its needs,
and to make the right requests to RefUpdate.  The RefUpdate API is
designed to help the application enforce CAS semantics, to avoid
race conditions and other ugly surprises.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2009-02-04 17:08 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-02-03 11:07 [JGIT] help needed to create a siimple commit Yann Simon
2009-02-03 15:51 ` Shawn O. Pearce
2009-02-04 16:10   ` Yann Simon
2009-02-04 17:07     ` Shawn O. Pearce

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).