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 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).