From: "Shawn O. Pearce" <spearce@spearce.org>
To: Robin Rosenberg <robin.rosenberg@dewire.com>
Cc: git@vger.kernel.org
Subject: Re: [EGIT PATCH 08/10] Add ref rename support to JGit
Date: Wed, 3 Jun 2009 09:43:30 -0700 [thread overview]
Message-ID: <20090603164330.GI3355@spearce.org> (raw)
In-Reply-To: <1243462137-24133-9-git-send-email-robin.rosenberg@dewire.com>
Robin Rosenberg <robin.rosenberg@dewire.com> wrote:
> Now refs can be renamed. The intent is that should be safe. Only the named
> refs and associated logs are updated. Any symbolic refs referring to the renames
> branches are unaffected, except HEAD, which is updated if the branch it refers
> to is being renamed.
...
> +// public void testRenameBranchCannotLockAFileHEADisToLockHead() throws IOException {
> +// an example following the rename failure pattern, but this one is ok!
> +// tryRenameWhenLocked("HEAD", "refs/heads/b", "refs/heads/new/name",
> +// "refs/heads/new/name");
> +// }
Commented out test case? Eh?
> +// public void testRenameBranchCannotLockAFileHEADisOtherLockHead() throws IOException {
> +// an example following the rename failure pattern, but this one is ok!
> +// tryRenameWhenLocked("HEAD", "refs/heads/b", "refs/heads/new/name",
> +// "refs/heads/a");
> +// }
Ditto.
> diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
...
> + RefRename newRename(String fromRef, String toRef) throws IOException {
> + refreshPackedRefs();
> + Ref f = readRefBasic(fromRef, 0);
> + Ref t = readRefBasic(toRef, 0);
> + if (t != null)
> + throw new IOException("Ref rename target exists: " + t.getName());
NAK, I'd prefer to have the RefRename return successfully,
but when we try to execute it, it has a result that fails with
RefUpdate.REJECTED.
> diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RefLogWriter.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RefLogWriter.java
...
> + static void renameTo(final Repository db, final RefUpdate from,
> + final RefUpdate to) throws IOException {
> + final File logdir = new File(db.getDirectory(), Constants.LOGS);
> + final File reflogFrom = new File(logdir, from.getName());
> + if (!reflogFrom.exists())
> + return;
> + final File reflogTo = new File(logdir, to.getName());
> + final File reflogToDir = reflogTo.getParentFile();
> + File tmp = new File(logdir,"tmp-renamed-log");
> + tmp.delete(); // if any exists
That's not thread safe. Most of the rest of JGit is actually
thread safe. I think we should be here too. We should use
a temporary file name inside logdir, one that isn't a legal
ref name at all. Maybe:
File tmp = File.createTempFile("tmp..renamed", "-log", logdir);
if (!reflogFrom.renameTo(tmp)) {
tmp.delete();
if (!reflogFrom.renameTo(tmp))
throw new IOException....
}
> + if (!reflogToDir.exists() && !reflogToDir.mkdirs()) {
> + throw new IOException("Cannot create directory " + reflogToDir);
> + }
> + if (!tmp.renameTo(reflogTo)) {
> + throw new IOException("Cannot rename (" + tmp + ")" + reflogFrom
> + + " to " + reflogTo);
> + }
If we fail here, should we attempt to put the tmp log file back
into the old name? Or leave it orphaned under the tmp file?
> diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RefRename.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RefRename.java
...
> + public Result rename() throws IOException {
> + Ref oldRef = oldFromDelete.db.readRef(Constants.HEAD);
> + boolean renameHEADtoo = oldRef != null
> + && oldRef.getName().equals(oldFromDelete.getName());
> + try {
> + Repository db = oldFromDelete.getRepository();
Style nit: Hoist to top of method, so oldRef init can use it.
> + RefLogWriter.renameTo(db, oldFromDelete,
> + newToUpdate);
Style nit: This fits on one line.
> + newToUpdate.setRefLogMessage(null, false);
> + RefUpdate tmpUpdateRef = oldFromDelete.db.getRepository().updateRef(
> + "RENAMED-REF");
Like the log, this isn't thread safe.
> + if (renameHEADtoo) {
> + try {
> + oldFromDelete.db.link(Constants.HEAD, "RENAMED-REF");
> + } catch (IOException e) {
> + RefLogWriter.renameTo(db,
> + newToUpdate, oldFromDelete);
> + return renameResult = Result.LOCK_FAILURE;
> + }
> + }
> + tmpUpdateRef.setNewObjectId(oldFromDelete.getOldObjectId());
We should also do:
oldFromDelete.setExpectedOldObjectId(oldFromDelete.getOldObjectId())
so that if the old ref was modified between the time we read it
and the time we delete it, we fail on the delete, and don't whack
a ref that was modified by another thread.
> + RefLogWriter.append(this, "jgit branch: renamed "
I think this should just be "renamed: $old to $new".
> + + db.shortenRefName(oldFromDelete.getName()) + " to "
> + + db.shortenRefName(newToUpdate.getName()));
> + return renameResult = Result.RENAMED;
> + } catch (RuntimeException e) {
> + throw e;
What's the point of this catch block?
> + } catch (IOException e) {
> + System.err.println(e);
Please don't print to System.err from such a low level method.
> diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java
...
> + /**
> + * The ref was renamed from another name
> + * <p>
> + */
> + RENAMED
Is a new state really necessary? Can't we use NEW on success?
After all, the dst is now created.
> }
>
> /** Repository the ref is stored in. */
> - private final RefDatabase db;
> + final RefDatabase db;
I wonder if this shouldn't just be a public accessor method; we expose
getRepository() on other application visible objects like RevWalk.
> /** Location of the loose file holding the value of this ref. */
> - private final File looseFile;
> + final File looseFile;
I don't see this used outside of the class, is it still necessary?
> /** Result of the update operation. */
> - private Result result = Result.NOT_ATTEMPTED;
> + Result result = Result.NOT_ATTEMPTED;
Ditto.
> + static void deleteEmptyDir(File dir, int depth) {
> + for (; depth > 0 && dir != null; depth--) {
> + if (dir.exists() && !dir.delete())
Why bother with a stat() call, just to do an rmdir()?
> - private static int count(final String s, final char c) {
> + static int count(final String s, final char c) {
Since all callers pass '/', maybe we should just change this to
use '/' as a constant in the loop and remove the char c parameter?
I think that would fix the nasty line wrapping in RefLogWriter too.
--
Shawn.
next prev parent reply other threads:[~2009-06-03 16:43 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-05-06 23:32 [EGIT PATCH 0/3] Rename refs Robin Rosenberg
2009-05-06 23:32 ` [EGIT PATCH 1/3] Add ref rename support to JGit Robin Rosenberg
2009-05-06 23:33 ` [EGIT PATCH 2/3] Use Constants.R_* in Branch dialog Robin Rosenberg
2009-05-06 23:33 ` [EGIT PATCH 3/3] Add ref rename support to the branch dialog Robin Rosenberg
2009-05-07 15:51 ` [EGIT PATCH 1/3] Add ref rename support to JGit Shawn O. Pearce
2009-05-19 23:13 ` [EGIT PATCH 0/6] Ref rename Robin Rosenberg
2009-05-19 23:13 ` [EGIT PATCH 1/6] Make sure we get the right storage for loose/pack/loose and packed refs Robin Rosenberg
2009-05-19 23:13 ` [EGIT PATCH 2/6] Add ref rename support to JGit Robin Rosenberg
2009-05-19 23:13 ` [EGIT PATCH 3/6] Add ref rename support to the branch dialog Robin Rosenberg
2009-05-19 23:13 ` [EGIT PATCH 4/6] Allow non-ASCII ref names when writing the packed-refs file Robin Rosenberg
2009-05-19 23:13 ` [EGIT PATCH 5/6] Use Constants.PACKED_REFS in RefWriter Robin Rosenberg
2009-05-19 23:13 ` [EGIT PATCH 6/6] Improve error reporting in the branch dialog Robin Rosenberg
2009-05-20 22:16 ` [EGIT PATCH 2/6] Add ref rename support to JGit Shawn O. Pearce
2009-05-27 22:08 ` [EGIT PATCH 00/10] Rename support Robin Rosenberg
2009-05-27 22:08 ` [EGIT PATCH 01/10] Make sure we get the right storage for loose/pack/loose and packed refs Robin Rosenberg
2009-05-27 22:08 ` [EGIT PATCH 02/10] Add a toString for debugging to RemoteRefUpdate Robin Rosenberg
2009-05-27 22:08 ` [EGIT PATCH 03/10] Add a toString to LockFile Robin Rosenberg
2009-05-27 22:08 ` [EGIT PATCH 04/10] Add more tests for RefUpdate Robin Rosenberg
2009-05-27 22:08 ` [EGIT PATCH 05/10] Do not write to the reflog unless the refupdate logmessage is set Robin Rosenberg
2009-05-27 22:08 ` [EGIT PATCH 06/10] Add a utility method for shortening long ref names to short ones Robin Rosenberg
2009-05-27 22:08 ` [EGIT PATCH 07/10] Set a nice reflog message in the branch command Robin Rosenberg
2009-05-27 22:08 ` [EGIT PATCH 08/10] Add ref rename support to JGit Robin Rosenberg
2009-05-27 22:08 ` [EGIT PATCH 09/10] Add ref rename support to the branch dialog Robin Rosenberg
2009-05-27 22:08 ` [EGIT PATCH 10/10] Improve error reporting in " Robin Rosenberg
2009-06-03 16:43 ` Shawn O. Pearce [this message]
2009-06-03 15:41 ` [EGIT PATCH 05/10] Do not write to the reflog unless the refupdate logmessage is set Shawn O. Pearce
2009-06-07 22:27 ` Robin Rosenberg
2009-06-07 22:44 ` Shawn O. Pearce
2009-05-20 21:43 ` [EGIT PATCH 1/6] Make sure we get the right storage for loose/pack/loose and packed refs Shawn O. Pearce
2009-05-21 15:22 ` Robin Rosenberg
2009-05-21 15:48 ` Shawn O. Pearce
2009-06-10 21:22 ` [EGIT PATCH v5 0/7] Ref rename support again Robin Rosenberg
2009-06-10 21:22 ` [EGIT PATCH v5 1/7] Add methods to RawParseUtils for scanning backwards Robin Rosenberg
2009-06-10 21:22 ` [EGIT PATCH v5 2/7] Add a ref log reader class Robin Rosenberg
2009-06-10 21:22 ` [EGIT PATCH v5 3/7] Do not write to the reflog unless the refupdate logmessage is set Robin Rosenberg
2009-06-10 21:22 ` [EGIT PATCH v5 4/7] Add ref rename support to JGit Robin Rosenberg
2009-06-10 21:22 ` [EGIT PATCH v5 5/7] Add ref rename support to the branch dialog Robin Rosenberg
2009-06-10 21:22 ` [EGIT PATCH v5 6/7] Improve error reporting in " Robin Rosenberg
2009-06-10 21:22 ` [EGIT PATCH v5 7/7] Remove a TAB from the message Egit generates into the reflog on commit Robin Rosenberg
2009-06-12 20:02 ` [EGIT PATCH v5 5/7] Add ref rename support to the branch dialog Shawn O. Pearce
2009-06-14 19:47 ` [EGIT PATCH v6 5a/7] Warn for unlocalized string literals in ui plugin Robin Rosenberg
2009-06-14 19:47 ` [EGIT PATCH v6 5b/6] Add ref rename support to the branch dialog Robin Rosenberg
2009-06-14 19:47 ` [EGIT PATCH v6 6/7] Improve error reporting in " Robin Rosenberg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090603164330.GI3355@spearce.org \
--to=spearce@spearce.org \
--cc=git@vger.kernel.org \
--cc=robin.rosenberg@dewire.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.