super.setUp();
diskRepo = createBareRepository();
- StoredConfig cfg = diskRepo.getConfig();
- cfg.load();
- cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true);
- cfg.save();
+ setLogAllRefUpdates(true);
refdir = (RefDirectory) diskRepo.getRefDatabase();
refdir.setRetrySleepMs(Arrays.asList(0, 0));
getLastReflog("refs/heads/branch"));
}
+ @Test
+ public void refLogNotWrittenWithoutConfigOption() throws Exception {
+ setLogAllRefUpdates(false);
+ writeRef("refs/heads/master", A);
+
+ Map<String, ReflogEntry> oldLogs =
+ getLastReflogs("refs/heads/master", "refs/heads/branch");
+ assertTrue(oldLogs.isEmpty());
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE));
+ execute(newBatchUpdate(cmds).setRefLogMessage("a reflog", false));
+
+ assertResults(cmds, OK, OK);
+ assertReflogUnchanged(oldLogs, "refs/heads/master");
+ assertReflogUnchanged(oldLogs, "refs/heads/branch");
+ }
+
+ @Test
+ public void forceRefLogInUpdate() throws Exception {
+ setLogAllRefUpdates(false);
+ writeRef("refs/heads/master", A);
+ assertTrue(
+ getLastReflogs("refs/heads/master", "refs/heads/branch").isEmpty());
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE));
+ execute(
+ newBatchUpdate(cmds)
+ .setRefLogMessage("a reflog", false)
+ .setForceRefLog(true));
+
+ assertResults(cmds, OK, OK);
+ assertReflogEquals(
+ reflog(A, B, new PersonIdent(diskRepo), "a reflog"),
+ getLastReflog("refs/heads/master"));
+ assertReflogEquals(
+ reflog(zeroId(), B, new PersonIdent(diskRepo), "a reflog"),
+ getLastReflog("refs/heads/branch"));
+ }
+
+ @Test
+ public void forceRefLogInCommand() throws Exception {
+ setLogAllRefUpdates(false);
+ writeRef("refs/heads/master", A);
+
+ Map<String, ReflogEntry> oldLogs =
+ getLastReflogs("refs/heads/master", "refs/heads/branch");
+ assertTrue(oldLogs.isEmpty());
+
+ List<ReceiveCommand> cmds = Arrays.asList(
+ new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+ new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE));
+ cmds.get(1).setForceRefLog(true);
+ execute(newBatchUpdate(cmds).setRefLogMessage("a reflog", false));
+
+ assertResults(cmds, OK, OK);
+ assertReflogUnchanged(oldLogs, "refs/heads/master");
+ assertReflogEquals(
+ reflog(zeroId(), B, new PersonIdent(diskRepo), "a reflog"),
+ getLastReflog("refs/heads/branch"));
+ }
+
@Test
public void packedRefsLockFailure() throws Exception {
writeLooseRef("refs/heads/master", A);
"refs/heads/branch", B);
}
+ private void setLogAllRefUpdates(boolean enable) throws Exception {
+ StoredConfig cfg = diskRepo.getConfig();
+ cfg.load();
+ cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, enable);
+ cfg.save();
+ }
+
private void writeLooseRef(String name, AnyObjectId id) throws IOException {
write(new File(diskRepo.getDirectory(), name), id.name() + "\n");
}
RefDirectory refs = (RefDirectory) db.getRefDatabase();
RefDirectoryUpdate update = refs.newUpdate(refName, true);
update.setNewObjectId(newId);
- refs.log(update, msg, true);
+ refs.log(false, update, msg, true);
}
private static class SubclassedId extends ObjectId {
if (ident == null) {
ident = new PersonIdent(refdb.getRepository());
}
- ReflogWriter w = refdb.getLogWriter();
for (ReceiveCommand cmd : commands) {
// Assume any pending commands have already been executed atomically.
if (cmd.getResult() != ReceiveCommand.Result.OK) {
}
}
try {
- w.log(name, cmd.getOldId(), cmd.getNewId(), ident, msg);
+ new ReflogWriter(refdb, isForceRefLog(cmd))
+ .log(name, cmd.getOldId(), cmd.getNewId(), ident, msg);
} catch (IOException e) {
// Ignore failures, but continue attempting to write more reflogs.
//
final File refsDir;
- private final ReflogWriter logWriter;
-
final File packedRefsFile;
final File logsDir;
final FS fs = db.getFS();
parent = db;
gitDir = db.getDirectory();
- logWriter = new ReflogWriter(this);
refsDir = fs.resolve(gitDir, R_REFS);
logsDir = fs.resolve(gitDir, LOGS);
logsRefsDir = fs.resolve(gitDir, LOGS + '/' + R_REFS);
return parent;
}
- ReflogWriter getLogWriter() {
- return logWriter;
+ ReflogWriter newLogWriter(boolean force) {
+ return new ReflogWriter(this, force);
}
/**
FileUtils.mkdir(refsDir);
FileUtils.mkdir(new File(refsDir, R_HEADS.substring(R_REFS.length())));
FileUtils.mkdir(new File(refsDir, R_TAGS.substring(R_REFS.length())));
- logWriter.create();
+ newLogWriter(false).create();
}
@Override
}
}
- void log(final RefUpdate update, final String msg, final boolean deref)
+ void log(boolean force, RefUpdate update, String msg, boolean deref)
throws IOException {
- logWriter.log(update, msg, deref);
+ newLogWriter(force).log(update, msg, deref);
}
private Ref resolve(final Ref ref, int depth, String prefix,
msg = strResult;
}
}
- database.log(this, msg, shouldDeref);
+ database.log(isForceRefLog(), this, msg, shouldDeref);
}
if (!lock.commit())
return Result.LOCK_FAILURE;
String msg = getRefLogMessage();
if (msg != null)
- database.log(this, msg, false);
+ database.log(isForceRefLog(), this, msg, false);
if (!lock.commit())
return Result.LOCK_FAILURE;
database.storedSymbolicRef(this, lock.getCommitSnapshot(), target);
/** Should the result value be appended to {@link #refLogMessage}. */
private boolean refLogIncludeResult;
+ /**
+ * Should reflogs be written even if the configured default for this ref is
+ * not to write it.
+ */
+ private boolean forceRefLog;
+
/** Push certificate associated with this update. */
private PushCertificate pushCert;
/**
* Set the message to include in the reflog.
* <p>
+ * Repository implementations may limit which reflogs are written by default,
+ * based on the project configuration. If a repo is not configured to write
+ * logs for this ref by default, setting the message alone may have no effect.
+ * To indicate that the repo should write logs for this update in spite of
+ * configured defaults, use {@link #setForceRefLog(boolean)}.
+ * <p>
* Describes the default for commands in this batch that do not override it
* with {@link ReceiveCommand#setRefLogMessage(String, boolean)}.
*
return this;
}
+ /**
+ * Force writing a reflog for the updated ref.
+ *
+ * @param force whether to force.
+ * @return {@code this}
+ * @since 4.9
+ */
+ public BatchRefUpdate setForceRefLog(boolean force) {
+ forceRefLog = force;
+ return this;
+ }
+
/**
* Check whether log has been disabled by {@link #disableRefLog()}.
*
return refLogMessage == null;
}
+ /**
+ * Check whether the reflog should be written regardless of repo defaults.
+ *
+ * @return whether force writing is enabled.
+ * @since 4.9
+ */
+ protected boolean isForceRefLog() {
+ return forceRefLog;
+ }
+
/**
* Request that all updates in this batch be performed atomically.
* <p>
} else {
ru.setRefLogIdent(refLogIdent);
ru.setRefLogMessage(getRefLogMessage(cmd), isRefLogIncludingResult(cmd));
+ ru.setForceRefLog(isForceRefLog(cmd));
}
ru.setPushCertificate(pushCert);
switch (cmd.getType()) {
? cmd.isRefLogIncludingResult() : isRefLogIncludingResult();
}
+ /**
+ * Check whether the reflog for a command should be written regardless of repo
+ * defaults.
+ *
+ * @param cmd
+ * specific command.
+ * @return whether force writing is enabled.
+ * @since 4.9
+ */
+ protected boolean isForceRefLog(ReceiveCommand cmd) {
+ Boolean isForceRefLog = cmd.isForceRefLog();
+ return isForceRefLog != null ? isForceRefLog.booleanValue()
+ : isForceRefLog();
+ }
+
@Override
public String toString() {
StringBuilder r = new StringBuilder();
/** Should the Result value be appended to {@link #refLogMessage}. */
private boolean refLogIncludeResult;
+ /**
+ * Should reflogs be written even if the configured default for this ref is
+ * not to write it.
+ */
+ private boolean forceRefLog;
+
/** Old value of the ref, obtained after we lock it. */
private ObjectId oldValue;
/**
* Set the message to include in the reflog.
+ * <p>
+ * Repository implementations may limit which reflogs are written by default,
+ * based on the project configuration. If a repo is not configured to write
+ * logs for this ref by default, setting the message alone may have no effect.
+ * To indicate that the repo should write logs for this update in spite of
+ * configured defaults, use {@link #setForceRefLog(boolean)}.
*
* @param msg
* the message to describe this change. It may be null if
refLogIncludeResult = false;
}
+ /**
+ * Force writing a reflog for the updated ref.
+ *
+ * @param force whether to force.
+ * @since 4.9
+ */
+ public void setForceRefLog(boolean force) {
+ forceRefLog = force;
+ }
+
+ /**
+ * Check whether the reflog should be written regardless of repo defaults.
+ *
+ * @return whether force writing is enabled.
+ * @since 4.9
+ */
+ protected boolean isForceRefLog() {
+ return forceRefLog;
+ }
+
/**
* The old value of the ref, prior to the update being attempted.
* <p>
private boolean refLogIncludeResult;
+ private Boolean forceRefLog;
+
private boolean typeIsCorrect;
/**
}
/**
- * Check whether this command has a custom reflog setting that should override
- * defaults in any containing {@link org.eclipse.jgit.lib.BatchRefUpdate}.
+ * Force writing a reflog for the updated ref.
+ *
+ * @param force whether to force.
+ * @since 4.9
+ */
+ public void setForceRefLog(boolean force) {
+ forceRefLog = Boolean.valueOf(force);
+ }
+
+ /**
+ * Check whether this command has a custom reflog message setting that should
+ * override defaults in any containing
+ * {@link org.eclipse.jgit.lib.BatchRefUpdate}.
+ * <p>
+ * Does not take into account whether {@code #setForceRefLog(boolean)} has
+ * been called.
*
* @return whether a custom reflog is set.
* @since 4.9
return refLogIncludeResult;
}
+ /**
+ * Check whether the reflog should be written regardless of repo defaults.
+ *
+ * @return whether force writing is enabled; null if {@code
+ * #setForceRefLog(boolean)} was never called.
+ * @since 4.9
+ */
+ @Nullable
+ public Boolean isForceRefLog() {
+ return forceRefLog;
+ }
+
/**
* Set the status of this command.
*