/*
 * Copyright (C) 2008-2010, Google Inc.
 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
 * and other copyright owners as documented in the project's IP log.
 *
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Distribution License v1.0 which
 * accompanies this distribution, is reproduced below, and is
 * available at http://www.eclipse.org/org/documents/edl-v10.php
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the following
 *   disclaimer in the documentation and/or other materials provided
 *   with the distribution.
 *
 * - Neither the name of the Eclipse Foundation, Inc. nor the
 *   names of its contributors may be used to endorse or promote
 *   products derived from this software without specific prior
 *   written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.eclipse.jgit.lib;

import java.io.IOException;
import java.text.MessageFormat;

import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.PushCertificate;
import org.eclipse.jgit.util.References;

Creates, updates or deletes any reference.
/** * Creates, updates or deletes any reference. */
public abstract class RefUpdate {
Status of an update request.

New values may be added to this enum in the future. Callers may assume that unknown values are failures, and may generally treat them the same as REJECTED_OTHER_REASON.

/** * Status of an update request. * <p> * New values may be added to this enum in the future. Callers may assume that * unknown values are failures, and may generally treat them the same as * {@link #REJECTED_OTHER_REASON}. */
public static enum Result {
The ref update/delete has not been attempted by the caller.
/** The ref update/delete has not been attempted by the caller. */
NOT_ATTEMPTED,
The ref could not be locked for update/delete.

This is generally a transient failure and is usually caused by another process trying to access the ref at the same time as this process was trying to update it. It is possible a future operation will be successful.

/** * The ref could not be locked for update/delete. * <p> * This is generally a transient failure and is usually caused by * another process trying to access the ref at the same time as this * process was trying to update it. It is possible a future operation * will be successful. */
LOCK_FAILURE,
Same value already stored.

Both the old value and the new value are identical. No change was necessary for an update. For delete the branch is removed.

/** * Same value already stored. * <p> * Both the old value and the new value are identical. No change was * necessary for an update. For delete the branch is removed. */
NO_CHANGE,
The ref was created locally for an update, but ignored for delete.

The ref did not exist when the update started, but it was created successfully with the new value.

/** * The ref was created locally for an update, but ignored for delete. * <p> * The ref did not exist when the update started, but it was created * successfully with the new value. */
NEW,
The ref had to be forcefully updated/deleted.

The ref already existed but its old value was not fully merged into the new value. The configuration permitted a forced update to take place, so ref now contains the new value. History associated with the objects not merged may no longer be reachable.

/** * The ref had to be forcefully updated/deleted. * <p> * The ref already existed but its old value was not fully merged into * the new value. The configuration permitted a forced update to take * place, so ref now contains the new value. History associated with the * objects not merged may no longer be reachable. */
FORCED,
The ref was updated/deleted in a fast-forward way.

The tracking ref already existed and its old value was fully merged into the new value. No history was made unreachable.

/** * The ref was updated/deleted in a fast-forward way. * <p> * The tracking ref already existed and its old value was fully merged * into the new value. No history was made unreachable. */
FAST_FORWARD,
Not a fast-forward and not stored.

The tracking ref already existed but its old value was not fully merged into the new value. The configuration did not allow a forced update/delete to take place, so ref still contains the old value. No previous history was lost.

Note: Despite the general name, this result only refers to the non-fast-forward case. For more general errors, see REJECTED_OTHER_REASON.

/** * Not a fast-forward and not stored. * <p> * The tracking ref already existed but its old value was not fully * merged into the new value. The configuration did not allow a forced * update/delete to take place, so ref still contains the old value. No * previous history was lost. * <p> * <em>Note:</em> Despite the general name, this result only refers to the * non-fast-forward case. For more general errors, see {@link * #REJECTED_OTHER_REASON}. */
REJECTED,
Rejected because trying to delete the current branch.

Has no meaning for update.

/** * Rejected because trying to delete the current branch. * <p> * Has no meaning for update. */
REJECTED_CURRENT_BRANCH,
The ref was probably not updated/deleted because of I/O error.

Unexpected I/O error occurred when writing new ref. Such error may result in uncertain state, but most probably ref was not updated.

This kind of error doesn't include LOCK_FAILURE, which is a different case.

/** * The ref was probably not updated/deleted because of I/O error. * <p> * Unexpected I/O error occurred when writing new ref. Such error may * result in uncertain state, but most probably ref was not updated. * <p> * This kind of error doesn't include {@link #LOCK_FAILURE}, which is a * different case. */
IO_FAILURE,
The ref was renamed from another name

/** * The ref was renamed from another name * <p> */
RENAMED,
One or more objects aren't in the repository.

This is severe indication of either repository corruption on the server side, or a bug in the client wherein the client did not supply all required objects during the pack transfer.

Since:4.9
/** * One or more objects aren't in the repository. * <p> * This is severe indication of either repository corruption on the * server side, or a bug in the client wherein the client did not supply * all required objects during the pack transfer. * * @since 4.9 */
REJECTED_MISSING_OBJECT,
Rejected for some other reason not covered by another enum value.
Since:4.9
/** * Rejected for some other reason not covered by another enum value. * * @since 4.9 */
REJECTED_OTHER_REASON; }
New value the caller wants this ref to have.
/** New value the caller wants this ref to have. */
private ObjectId newValue;
Does this specification ask for forced updated (rewind/reset)?
/** Does this specification ask for forced updated (rewind/reset)? */
private boolean force;
Identity to record action as within the reflog.
/** Identity to record action as within the reflog. */
private PersonIdent refLogIdent;
Message the caller wants included in the reflog.
/** Message the caller wants included in the reflog. */
private String refLogMessage;
Should the Result value be appended to refLogMessage.
/** 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.
/** * 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.
/** Old value of the ref, obtained after we lock it. */
private ObjectId oldValue;
If non-null, the value oldValue must have to continue.
/** If non-null, the value {@link #oldValue} must have to continue. */
private ObjectId expValue;
Result of the update operation.
/** Result of the update operation. */
private Result result = Result.NOT_ATTEMPTED;
Push certificate associated with this update.
/** Push certificate associated with this update. */
private PushCertificate pushCert; private final Ref ref;
Is this RefUpdate detaching a symbolic ref? We need this info since this.ref will normally be peeled of in case of detaching a symbolic ref (HEAD for example). Without this flag we cannot decide whether the ref has to be updated or not in case when it was a symbolic ref and the newValue == oldValue.
/** * Is this RefUpdate detaching a symbolic ref? * * We need this info since this.ref will normally be peeled of in case of * detaching a symbolic ref (HEAD for example). * * Without this flag we cannot decide whether the ref has to be updated or * not in case when it was a symbolic ref and the newValue == oldValue. */
private boolean detachingSymbolicRef; private boolean checkConflicting = true;
Construct a new update operation for the reference.

ref.getObjectId() will be used to seed getOldObjectId(), which callers can use as part of their own update logic.

Params:
  • ref – the reference that will be updated by this operation.
/** * Construct a new update operation for the reference. * <p> * {@code ref.getObjectId()} will be used to seed {@link #getOldObjectId()}, * which callers can use as part of their own update logic. * * @param ref * the reference that will be updated by this operation. */
protected RefUpdate(Ref ref) { this.ref = ref; oldValue = ref.getObjectId(); refLogMessage = ""; //$NON-NLS-1$ }
Get the reference database this update modifies.
Returns:the reference database this update modifies.
/** * Get the reference database this update modifies. * * @return the reference database this update modifies. */
protected abstract RefDatabase getRefDatabase();
Get the repository storing the database's objects.
Returns:the repository storing the database's objects.
/** * Get the repository storing the database's objects. * * @return the repository storing the database's objects. */
protected abstract Repository getRepository();
Try to acquire the lock on the reference.

If the locking was successful the implementor must set the current identity value by calling setOldObjectId(ObjectId).

Params:
  • deref – true if the lock should be taken against the leaf level reference; false if it should be taken exactly against the current reference.
Throws:
  • IOException – the lock couldn't be taken due to an unexpected storage failure, and not because of a concurrent update.
Returns:true if the lock was acquired and the reference is likely protected from concurrent modification; false if it failed.
/** * Try to acquire the lock on the reference. * <p> * If the locking was successful the implementor must set the current * identity value by calling {@link #setOldObjectId(ObjectId)}. * * @param deref * true if the lock should be taken against the leaf level * reference; false if it should be taken exactly against the * current reference. * @return true if the lock was acquired and the reference is likely * protected from concurrent modification; false if it failed. * @throws java.io.IOException * the lock couldn't be taken due to an unexpected storage * failure, and not because of a concurrent update. */
protected abstract boolean tryLock(boolean deref) throws IOException;
Releases the lock taken by tryLock if it succeeded.
/** * Releases the lock taken by {@link #tryLock} if it succeeded. */
protected abstract void unlock();
Do update
Params:
  • desiredResult – a Result object.
Throws:
Returns:result
/** * Do update * * @param desiredResult * a {@link org.eclipse.jgit.lib.RefUpdate.Result} object. * @return {@code result} * @throws java.io.IOException */
protected abstract Result doUpdate(Result desiredResult) throws IOException;
Do delete
Params:
  • desiredResult – a Result object.
Throws:
Returns:result
/** * Do delete * * @param desiredResult * a {@link org.eclipse.jgit.lib.RefUpdate.Result} object. * @return {@code result} * @throws java.io.IOException */
protected abstract Result doDelete(Result desiredResult) throws IOException;
Do link
Params:
Throws:
Returns:Result.NEW on success.
/** * Do link * * @param target * a {@link java.lang.String} object. * @return {@link org.eclipse.jgit.lib.RefUpdate.Result#NEW} on success. * @throws java.io.IOException */
protected abstract Result doLink(String target) throws IOException;
Get the name of the ref this update will operate on.
Returns:name of underlying ref.
/** * Get the name of the ref this update will operate on. * * @return name of underlying ref. */
public String getName() { return getRef().getName(); }
Get the reference this update will create or modify.
Returns:the reference this update will create or modify.
/** * Get the reference this update will create or modify. * * @return the reference this update will create or modify. */
public Ref getRef() { return ref; }
Get the new value the ref will be (or was) updated to.
Returns:new value. Null if the caller has not configured it.
/** * Get the new value the ref will be (or was) updated to. * * @return new value. Null if the caller has not configured it. */
public ObjectId getNewObjectId() { return newValue; }
Tells this RefUpdate that it is actually detaching a symbolic ref.
/** * Tells this RefUpdate that it is actually detaching a symbolic ref. */
public void setDetachingSymbolicRef() { detachingSymbolicRef = true; }
Return whether this update is actually detaching a symbolic ref.
Returns:true if detaching a symref.
Since:4.9
/** * Return whether this update is actually detaching a symbolic ref. * * @return true if detaching a symref. * @since 4.9 */
public boolean isDetachingSymbolicRef() { return detachingSymbolicRef; }
Set the new value the ref will update to.
Params:
  • id – the new value.
/** * Set the new value the ref will update to. * * @param id * the new value. */
public void setNewObjectId(AnyObjectId id) { newValue = id.copy(); }
Get the expected value of the ref after the lock is taken, but before update occurs.
Returns:the expected value of the ref after the lock is taken, but before update occurs. Null to avoid the compare and swap test. Use ObjectId.zeroId() to indicate expectation of a non-existant ref.
/** * Get the expected value of the ref after the lock is taken, but before * update occurs. * * @return the expected value of the ref after the lock is taken, but before * update occurs. Null to avoid the compare and swap test. Use * {@link org.eclipse.jgit.lib.ObjectId#zeroId()} to indicate * expectation of a non-existant ref. */
public ObjectId getExpectedOldObjectId() { return expValue; }
Set the expected value of the ref after the lock is taken, but before update occurs.
Params:
  • id – the expected value of the ref after the lock is taken, but before update occurs. Null to avoid the compare and swap test. Use ObjectId.zeroId() to indicate expectation of a non-existant ref.
/** * Set the expected value of the ref after the lock is taken, but before * update occurs. * * @param id * the expected value of the ref after the lock is taken, but * before update occurs. Null to avoid the compare and swap test. * Use {@link org.eclipse.jgit.lib.ObjectId#zeroId()} to indicate * expectation of a non-existant ref. */
public void setExpectedOldObjectId(AnyObjectId id) { expValue = id != null ? id.toObjectId() : null; }
Check if this update wants to forcefully change the ref.
Returns:true if this update should ignore merge tests.
/** * Check if this update wants to forcefully change the ref. * * @return true if this update should ignore merge tests. */
public boolean isForceUpdate() { return force; }
Set if this update wants to forcefully change the ref.
Params:
  • b – true if this update should ignore merge tests.
/** * Set if this update wants to forcefully change the ref. * * @param b * true if this update should ignore merge tests. */
public void setForceUpdate(boolean b) { force = b; }
Get identity of the user making the change in the reflog.
Returns:identity of the user making the change in the reflog.
/** * Get identity of the user making the change in the reflog. * * @return identity of the user making the change in the reflog. */
public PersonIdent getRefLogIdent() { return refLogIdent; }
Set the identity of the user appearing in the reflog.

The timestamp portion of the identity is ignored. A new identity with the current timestamp will be created automatically when the update occurs and the log record is written.

Params:
  • pi – identity of the user. If null the identity will be automatically determined based on the repository configuration.
/** * Set the identity of the user appearing in the reflog. * <p> * The timestamp portion of the identity is ignored. A new identity with the * current timestamp will be created automatically when the update occurs * and the log record is written. * * @param pi * identity of the user. If null the identity will be * automatically determined based on the repository * configuration. */
public void setRefLogIdent(PersonIdent pi) { refLogIdent = pi; }
Get the message to include in the reflog.
Returns:message the caller wants to include in the reflog; null if the update should not be logged.
/** * Get the message to include in the reflog. * * @return message the caller wants to include in the reflog; null if the * update should not be logged. */
public String getRefLogMessage() { return refLogMessage; }
Whether the ref log message should show the result.
Returns:true if the ref log message should show the result.
/** * Whether the ref log message should show the result. * * @return {@code true} if the ref log message should show the result. */
protected boolean isRefLogIncludingResult() { return refLogIncludeResult; }
Set the message to include in the reflog.

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 setForceRefLog(boolean).

Params:
  • msg – the message to describe this change. It may be null if appendStatus is null in order not to append to the reflog
  • appendStatus – true if the status of the ref change (fast-forward or forced-update) should be appended to the user supplied message.
/** * 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 * appendStatus is null in order not to append to the reflog * @param appendStatus * true if the status of the ref change (fast-forward or * forced-update) should be appended to the user supplied * message. */
public void setRefLogMessage(String msg, boolean appendStatus) { if (msg == null && !appendStatus) disableRefLog(); else if (msg == null && appendStatus) { refLogMessage = ""; //$NON-NLS-1$ refLogIncludeResult = true; } else { refLogMessage = msg; refLogIncludeResult = appendStatus; } }
Don't record this update in the ref's associated reflog.
/** * Don't record this update in the ref's associated reflog. */
public void disableRefLog() { refLogMessage = null; refLogIncludeResult = false; }
Force writing a reflog for the updated ref.
Params:
  • force – whether to force.
Since:4.9
/** * 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.
Returns:whether force writing is enabled.
Since:4.9
/** * 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.

This value may differ before and after the update method. Initially it is populated with the value of the ref before the lock is taken, but the old value may change if someone else modified the ref between the time we last read it and when the ref was locked for update.

Returns:the value of the ref prior to the update being attempted; null if the updated has not been attempted yet.
/** * The old value of the ref, prior to the update being attempted. * <p> * This value may differ before and after the update method. Initially it is * populated with the value of the ref before the lock is taken, but the old * value may change if someone else modified the ref between the time we * last read it and when the ref was locked for update. * * @return the value of the ref prior to the update being attempted; null if * the updated has not been attempted yet. */
public ObjectId getOldObjectId() { return oldValue; }
Set the old value of the ref.
Params:
  • old – the old value.
/** * Set the old value of the ref. * * @param old * the old value. */
protected void setOldObjectId(ObjectId old) { oldValue = old; }
Set a push certificate associated with this update.

This usually includes a command to update this ref, but is not required to.

Params:
  • cert – push certificate, may be null.
Since:4.1
/** * Set a push certificate associated with this update. * <p> * This usually includes a command to update this ref, but is not required to. * * @param cert * push certificate, may be null. * @since 4.1 */
public void setPushCertificate(PushCertificate cert) { pushCert = cert; }
Set the push certificate associated with this update.

This usually includes a command to update this ref, but is not required to.

Returns:push certificate, may be null.
Since:4.1
/** * Set the push certificate associated with this update. * <p> * This usually includes a command to update this ref, but is not required to. * * @return push certificate, may be null. * @since 4.1 */
protected PushCertificate getPushCertificate() { return pushCert; }
Get the status of this update.

The same value that was previously returned from an update method.

Returns:the status of the update.
/** * Get the status of this update. * <p> * The same value that was previously returned from an update method. * * @return the status of the update. */
public Result getResult() { return result; } private void requireCanDoUpdate() { if (newValue == null) throw new IllegalStateException(JGitText.get().aNewObjectIdIsRequired); }
Force the ref to take the new value.

This is just a convenient helper for setting the force flag, and as such the merge test is performed.

Throws:
  • IOException – an unexpected IO error occurred while writing changes.
Returns:the result status of the update.
/** * Force the ref to take the new value. * <p> * This is just a convenient helper for setting the force flag, and as such * the merge test is performed. * * @return the result status of the update. * @throws java.io.IOException * an unexpected IO error occurred while writing changes. */
public Result forceUpdate() throws IOException { force = true; return update(); }
Gracefully update the ref to the new value.

Merge test will be performed according to isForceUpdate().

This is the same as:

return update(new RevWalk(getRepository()));
Throws:
  • IOException – an unexpected IO error occurred while writing changes.
Returns:the result status of the update.
/** * Gracefully update the ref to the new value. * <p> * Merge test will be performed according to {@link #isForceUpdate()}. * <p> * This is the same as: * * <pre> * return update(new RevWalk(getRepository())); * </pre> * * @return the result status of the update. * @throws java.io.IOException * an unexpected IO error occurred while writing changes. */
public Result update() throws IOException { try (RevWalk rw = new RevWalk(getRepository())) { rw.setRetainBody(false); return update(rw); } }
Gracefully update the ref to the new value.

Merge test will be performed according to isForceUpdate().

Params:
  • walk – a RevWalk instance this update command can borrow to perform the merge test. The walk will be reset to perform the test.
Throws:
  • IOException – an unexpected IO error occurred while writing changes.
Returns:the result status of the update.
/** * Gracefully update the ref to the new value. * <p> * Merge test will be performed according to {@link #isForceUpdate()}. * * @param walk * a RevWalk instance this update command can borrow to perform * the merge test. The walk will be reset to perform the test. * @return the result status of the update. * @throws java.io.IOException * an unexpected IO error occurred while writing changes. */
public Result update(RevWalk walk) throws IOException { requireCanDoUpdate(); try { return result = updateImpl(walk, new Store() { @Override Result execute(Result status) throws IOException { if (status == Result.NO_CHANGE) return status; return doUpdate(status); } }); } catch (IOException x) { result = Result.IO_FAILURE; throw x; } }
Delete the ref.

This is the same as:

return delete(new RevWalk(getRepository()));
Throws:
Returns:the result status of the delete.
/** * Delete the ref. * <p> * This is the same as: * * <pre> * return delete(new RevWalk(getRepository())); * </pre> * * @return the result status of the delete. * @throws java.io.IOException */
public Result delete() throws IOException { try (RevWalk rw = new RevWalk(getRepository())) { rw.setRetainBody(false); return delete(rw); } }
Delete the ref.
Params:
  • walk – a RevWalk instance this delete command can borrow to perform the merge test. The walk will be reset to perform the test.
Throws:
Returns:the result status of the delete.
/** * Delete the ref. * * @param walk * a RevWalk instance this delete command can borrow to perform * the merge test. The walk will be reset to perform the test. * @return the result status of the delete. * @throws java.io.IOException */
public Result delete(RevWalk walk) throws IOException { final String myName = detachingSymbolicRef ? getRef().getName() : getRef().getLeaf().getName(); if (myName.startsWith(Constants.R_HEADS) && !getRepository().isBare()) { // Don't allow the currently checked out branch to be deleted. Ref head = getRefDatabase().exactRef(Constants.HEAD); while (head != null && head.isSymbolic()) { head = head.getTarget(); if (myName.equals(head.getName())) return result = Result.REJECTED_CURRENT_BRANCH; } } try { return result = updateImpl(walk, new Store() { @Override Result execute(Result status) throws IOException { return doDelete(status); } }); } catch (IOException x) { result = Result.IO_FAILURE; throw x; } }
Replace this reference with a symbolic reference to another reference.

This exact reference (not its traversed leaf) is replaced with a symbolic reference to the requested name.

Params:
  • target – name of the new target for this reference. The new target name must be absolute, so it must begin with refs/.
Throws:
Returns:Result.NEW or Result.FORCED on success.
/** * Replace this reference with a symbolic reference to another reference. * <p> * This exact reference (not its traversed leaf) is replaced with a symbolic * reference to the requested name. * * @param target * name of the new target for this reference. The new target name * must be absolute, so it must begin with {@code refs/}. * @return {@link org.eclipse.jgit.lib.RefUpdate.Result#NEW} or * {@link org.eclipse.jgit.lib.RefUpdate.Result#FORCED} on success. * @throws java.io.IOException */
public Result link(String target) throws IOException { if (!target.startsWith(Constants.R_REFS)) throw new IllegalArgumentException(MessageFormat.format(JGitText.get().illegalArgumentNotA, Constants.R_REFS)); if (checkConflicting && getRefDatabase().isNameConflicting(getName())) return Result.LOCK_FAILURE; try { if (!tryLock(false)) return Result.LOCK_FAILURE; final Ref old = getRefDatabase().exactRef(getName()); if (old != null && old.isSymbolic()) { final Ref dst = old.getTarget(); if (target.equals(dst.getName())) return result = Result.NO_CHANGE; } if (old != null && old.getObjectId() != null) setOldObjectId(old.getObjectId()); final Ref dst = getRefDatabase().exactRef(target); if (dst != null && dst.getObjectId() != null) setNewObjectId(dst.getObjectId()); return result = doLink(target); } catch (IOException x) { result = Result.IO_FAILURE; throw x; } finally { unlock(); } } private Result updateImpl(RevWalk walk, Store store) throws IOException { RevObject newObj; RevObject oldObj; // don't make expensive conflict check if this is an existing Ref if (oldValue == null && checkConflicting && getRefDatabase().isNameConflicting(getName())) { return Result.LOCK_FAILURE; } try { // If we're detaching a symbolic reference, we should update the reference // itself. Otherwise, we will update the leaf reference, which should be // an ObjectIdRef. if (!tryLock(!detachingSymbolicRef)) { return Result.LOCK_FAILURE; } if (expValue != null) { final ObjectId o; o = oldValue != null ? oldValue : ObjectId.zeroId(); if (!AnyObjectId.isEqual(expValue, o)) { return Result.LOCK_FAILURE; } } try { newObj = safeParseNew(walk, newValue); } catch (MissingObjectException e) { return Result.REJECTED_MISSING_OBJECT; } if (oldValue == null) { return store.execute(Result.NEW); } oldObj = safeParseOld(walk, oldValue); if (References.isSameObject(newObj, oldObj) && !detachingSymbolicRef) { return store.execute(Result.NO_CHANGE); } if (isForceUpdate()) { return store.execute(Result.FORCED); } if (newObj instanceof RevCommit && oldObj instanceof RevCommit) { if (walk.isMergedInto((RevCommit) oldObj, (RevCommit) newObj)) { return store.execute(Result.FAST_FORWARD); } } return Result.REJECTED; } finally { unlock(); } }
Enable/disable the check for conflicting ref names. By default conflicts are checked explicitly.
Params:
  • check – whether to enable the check for conflicting ref names.
Since:3.0
/** * Enable/disable the check for conflicting ref names. By default conflicts * are checked explicitly. * * @param check * whether to enable the check for conflicting ref names. * @since 3.0 */
public void setCheckConflicting(boolean check) { checkConflicting = check; } private static RevObject safeParseNew(RevWalk rw, AnyObjectId newId) throws IOException { if (newId == null || ObjectId.zeroId().equals(newId)) { return null; } return rw.parseAny(newId); } private static RevObject safeParseOld(RevWalk rw, AnyObjectId oldId) throws IOException { try { return oldId != null ? rw.parseAny(oldId) : null; } catch (MissingObjectException e) { // We can expect some old objects to be missing, like if we are trying to // force a deletion of a branch and the object it points to has been // pruned from the database due to freak corruption accidents (it happens // with 'git new-work-dir'). return null; } }
Handle the abstraction of storing a ref update. This is because both updating and deleting of a ref have merge testing in common.
/** * Handle the abstraction of storing a ref update. This is because both * updating and deleting of a ref have merge testing in common. */
private static abstract class Store { abstract Result execute(Result status) throws IOException; } }