private void execute(final ReceiveCommand cmd) { try { final RefUpdate ru = db.updateRef(cmd.getRefName()); ru.setRefLogIdent(getRefLogIdent()); switch (cmd.getType()) { case DELETE: if (!ObjectId.zeroId().equals(cmd.getOldId())) { // We can only do a CAS style delete if the client // didn't bork its delete request by sending the // wrong zero id rather than the advertised one. // ru.setExpectedOldObjectId(cmd.getOldId()); } ru.setForceUpdate(true); status(cmd, ru.delete(walk)); break; case CREATE: case UPDATE: case UPDATE_NONFASTFORWARD: ru.setForceUpdate(isAllowNonFastForwards()); ru.setExpectedOldObjectId(cmd.getOldId()); ru.setNewObjectId(cmd.getNewId()); ru.setRefLogMessage("push", true); status(cmd, ru.update(walk)); break; } } catch (IOException err) { cmd.setResult( Result.REJECTED_OTHER_REASON, MessageFormat.format(JGitText.get().lockError, err.getMessage())); } }
/** * Update a reference to point to an object. * * @param <T> type of the target object. * @param ref the name of the reference to update to. If {@code ref} does not start with {@code * refs/} and is not the magic names {@code HEAD} {@code FETCH_HEAD} or {@code MERGE_HEAD}, * then {@code refs/heads/} will be prefixed in front of the given name, thereby assuming it * is a branch. * @param obj the target object. * @return the target object. * @throws Exception */ public <T extends AnyObjectId> T update(String ref, T obj) throws Exception { if (Constants.HEAD.equals(ref)) { // nothing } else if ("FETCH_HEAD".equals(ref)) { // nothing } else if ("MERGE_HEAD".equals(ref)) { // nothing } else if (ref.startsWith(Constants.R_REFS)) { // nothing } else ref = Constants.R_HEADS + ref; RefUpdate u = db.updateRef(ref); u.setNewObjectId(obj); switch (u.forceUpdate()) { case FAST_FORWARD: case FORCED: case NEW: case NO_CHANGE: updateServerInfo(); return obj; default: throw new IOException("Cannot write " + ref + " " + u.getResult()); } }
@NotNull @Override public Repository createRepository(@NotNull File file, @NotNull String branch) throws IOException { final Repository repository = createRepository(file); final ObjectId revision = createFirstRevision(repository); final RefUpdate refUpdate = repository.updateRef(Constants.R_HEADS + branch); refUpdate.setNewObjectId(revision); refUpdate.update(); return repository; }
private boolean commitIndex(Repository db, DirCache index, String author, String message) throws IOException, ConcurrentRefUpdateException { boolean success = false; ObjectId headId = db.resolve(BRANCH + "^{commit}"); if (headId == null) { // create the branch createTicketsBranch(db); headId = db.resolve(BRANCH + "^{commit}"); } try (ObjectInserter odi = db.newObjectInserter()) { // Create the in-memory index of the new/updated ticket ObjectId indexTreeId = index.writeTree(odi); // Create a commit object PersonIdent ident = new PersonIdent(author, "gitblit@localhost"); CommitBuilder commit = new CommitBuilder(); commit.setAuthor(ident); commit.setCommitter(ident); commit.setEncoding(Constants.ENCODING); commit.setMessage(message); commit.setParentId(headId); commit.setTreeId(indexTreeId); // Insert the commit into the repository ObjectId commitId = odi.insert(commit); odi.flush(); try (RevWalk revWalk = new RevWalk(db)) { RevCommit revCommit = revWalk.parseCommit(commitId); RefUpdate ru = db.updateRef(BRANCH); ru.setNewObjectId(commitId); ru.setExpectedOldObjectId(headId); ru.setRefLogMessage("commit: " + revCommit.getShortMessage(), false); Result rc = ru.forceUpdate(); switch (rc) { case NEW: case FORCED: case FAST_FORWARD: success = true; break; case REJECTED: case LOCK_FAILURE: throw new ConcurrentRefUpdateException( JGitText.get().couldNotLockHEAD, ru.getRef(), rc); default: throw new JGitInternalException( MessageFormat.format( JGitText.get().updatingRefFailed, BRANCH, commitId.toString(), rc)); } } } return success; }
/** * Creates a new branch * * @param refName starting point for the new branch * @param newRefName * @throws IOException */ public void createBranch(String refName, String newRefName) throws IOException { RefUpdate updateRef; updateRef = repository.updateRef(newRefName); Ref startRef = repository.getRef(refName); ObjectId startAt = repository.resolve(refName); String startBranch; if (startRef != null) startBranch = refName; else startBranch = startAt.name(); startBranch = Repository.shortenRefName(startBranch); updateRef.setNewObjectId(startAt); updateRef.setRefLogMessage("branch: Created from " + startBranch, false); // $NON-NLS-1$ updateRef.update(); }
private void doCheckout(final Ref branch) throws IOException { if (branch == null) throw die(CLIText.get().cannotChekoutNoHeadsAdvertisedByRemote); if (!Constants.HEAD.equals(branch.getName())) { RefUpdate u = db.updateRef(Constants.HEAD); u.disableRefLog(); u.link(branch.getName()); } final RevCommit commit = parseCommit(branch); final RefUpdate u = db.updateRef(Constants.HEAD); u.setNewObjectId(commit); u.forceUpdate(); DirCache dc = db.lockDirCache(); DirCacheCheckout co = new DirCacheCheckout(db, dc, commit.getTree()); co.checkout(); }
@Test public void testListRemote_Smart_DetachedHEAD() throws Exception { Repository src = remoteRepository.getRepository(); RefUpdate u = src.updateRef(Constants.HEAD, true); RevCommit Q = remoteRepository.commit().message("Q").create(); u.setNewObjectId(Q); assertEquals(RefUpdate.Result.FORCED, u.forceUpdate()); Repository dst = createBareRepository(); Ref head; Transport t = Transport.open(dst, smartAuthNoneURI); try { FetchConnection c = t.openFetch(); try { head = c.getRef(Constants.HEAD); } finally { c.close(); } } finally { t.close(); } assertNotNull("has " + Constants.HEAD, head); assertEquals(Q, head.getObjectId()); }
@Test public void testMergeEmptyBranches() throws IOException, NoHeadException, NoMessageException, ConcurrentRefUpdateException, JGitInternalException, WrongRepositoryStateException { Git git = new Git(db); git.commit().setMessage("initial commit").call(); RefUpdate r = db.updateRef("refs/heads/side"); r.setNewObjectId(db.resolve(Constants.HEAD)); assertEquals(r.forceUpdate(), RefUpdate.Result.NEW); RevCommit second = git.commit().setMessage("second commit").setCommitter(committer).call(); db.updateRef(Constants.HEAD).link("refs/heads/side"); RevCommit firstSide = git.commit().setMessage("first side commit").setAuthor(author).call(); write( new File(db.getDirectory(), Constants.MERGE_HEAD), ObjectId.toString(db.resolve("refs/heads/master"))); write(new File(db.getDirectory(), Constants.MERGE_MSG), "merging"); RevCommit commit = git.commit().call(); RevCommit[] parents = commit.getParents(); assertEquals(parents[0], firstSide); assertEquals(parents[1], second); assertTrue(parents.length == 2); }
/** * Executes the {@code commit} command with all the options and parameters collected by the setter * methods of this class. Each instance of this class should only be used for one invocation of * the command (means: one call to {@link #call()}) * * @return a {@link RevCommit} object representing the successful commit. * @throws NoHeadException when called on a git repo without a HEAD reference * @throws NoMessageException when called without specifying a commit message * @throws UnmergedPathsException when the current index contained unmerged paths (conflicts) * @throws ConcurrentRefUpdateException when HEAD or branch ref is updated concurrently by someone * else * @throws WrongRepositoryStateException when repository is not in the right state for committing * @throws AbortedByHookException if there are either pre-commit or commit-msg hooks present in * the repository and one of them rejects the commit. */ public RevCommit call() throws GitAPIException, NoHeadException, NoMessageException, UnmergedPathsException, ConcurrentRefUpdateException, WrongRepositoryStateException, AbortedByHookException { checkCallable(); Collections.sort(only); try (RevWalk rw = new RevWalk(repo)) { RepositoryState state = repo.getRepositoryState(); if (!state.canCommit()) throw new WrongRepositoryStateException( MessageFormat.format(JGitText.get().cannotCommitOnARepoWithState, state.name())); if (!noVerify) { Hooks.preCommit(repo, hookOutRedirect).call(); } processOptions(state, rw); if (all && !repo.isBare() && repo.getWorkTree() != null) { try (Git git = new Git(repo)) { git.add() .addFilepattern(".") // $NON-NLS-1$ .setUpdate(true) .call(); } catch (NoFilepatternException e) { // should really not happen throw new JGitInternalException(e.getMessage(), e); } } Ref head = repo.getRef(Constants.HEAD); if (head == null) throw new NoHeadException(JGitText.get().commitOnRepoWithoutHEADCurrentlyNotSupported); // determine the current HEAD and the commit it is referring to ObjectId headId = repo.resolve(Constants.HEAD + "^{commit}"); // $NON-NLS-1$ if (headId == null && amend) throw new WrongRepositoryStateException(JGitText.get().commitAmendOnInitialNotPossible); if (headId != null) if (amend) { RevCommit previousCommit = rw.parseCommit(headId); for (RevCommit p : previousCommit.getParents()) parents.add(p.getId()); if (author == null) author = previousCommit.getAuthorIdent(); } else { parents.add(0, headId); } if (!noVerify) { message = Hooks.commitMsg(repo, hookOutRedirect).setCommitMessage(message).call(); } // lock the index DirCache index = repo.lockDirCache(); try (ObjectInserter odi = repo.newObjectInserter()) { if (!only.isEmpty()) index = createTemporaryIndex(headId, index, rw); // Write the index as tree to the object database. This may // fail for example when the index contains unmerged paths // (unresolved conflicts) ObjectId indexTreeId = index.writeTree(odi); if (insertChangeId) insertChangeId(indexTreeId); // Create a Commit object, populate it and write it CommitBuilder commit = new CommitBuilder(); commit.setCommitter(committer); commit.setAuthor(author); commit.setMessage(message); commit.setParentIds(parents); commit.setTreeId(indexTreeId); ObjectId commitId = odi.insert(commit); odi.flush(); RevCommit revCommit = rw.parseCommit(commitId); RefUpdate ru = repo.updateRef(Constants.HEAD); ru.setNewObjectId(commitId); if (reflogComment != null) { ru.setRefLogMessage(reflogComment, false); } else { String prefix = amend ? "commit (amend): " //$NON-NLS-1$ : parents.size() == 0 ? "commit (initial): " //$NON-NLS-1$ : "commit: "; //$NON-NLS-1$ ru.setRefLogMessage(prefix + revCommit.getShortMessage(), false); } if (headId != null) ru.setExpectedOldObjectId(headId); else ru.setExpectedOldObjectId(ObjectId.zeroId()); Result rc = ru.forceUpdate(); switch (rc) { case NEW: case FORCED: case FAST_FORWARD: { setCallable(false); if (state == RepositoryState.MERGING_RESOLVED || isMergeDuringRebase(state)) { // Commit was successful. Now delete the files // used for merge commits repo.writeMergeCommitMsg(null); repo.writeMergeHeads(null); } else if (state == RepositoryState.CHERRY_PICKING_RESOLVED) { repo.writeMergeCommitMsg(null); repo.writeCherryPickHead(null); } else if (state == RepositoryState.REVERTING_RESOLVED) { repo.writeMergeCommitMsg(null); repo.writeRevertHead(null); } return revCommit; } case REJECTED: case LOCK_FAILURE: throw new ConcurrentRefUpdateException( JGitText.get().couldNotLockHEAD, ru.getRef(), rc); default: throw new JGitInternalException( MessageFormat.format( JGitText.get().updatingRefFailed, Constants.HEAD, commitId.toString(), rc)); } } finally { index.unlock(); } } catch (UnmergedPathException e) { throw new UnmergedPathsException(e); } catch (IOException e) { throw new JGitInternalException( JGitText.get().exceptionCaughtDuringExecutionOfCommitCommand, e); } }
/** * Update the submodules in one branch of one repository. * * @param subscriber the branch of the repository which should be changed. * @param updates submodule updates which should be updated to. * @throws SubmoduleException */ private void updateGitlinks( ReviewDb db, Branch.NameKey subscriber, Collection<SubmoduleSubscription> updates) throws SubmoduleException { PersonIdent author = null; Repository pdb = null; RevWalk recRw = null; StringBuilder msgbuf = new StringBuilder("Updated git submodules\n\n"); try { boolean sameAuthorForAll = true; pdb = repoManager.openRepository(subscriber.getParentKey()); if (pdb.getRef(subscriber.get()) == null) { throw new SubmoduleException( "The branch was probably deleted from the subscriber repository"); } DirCache dc = readTree(pdb, pdb.getRef(subscriber.get())); DirCacheEditor ed = dc.editor(); for (SubmoduleSubscription s : updates) { try (Repository subrepo = repoManager.openRepository(s.getSubmodule().getParentKey()); RevWalk rw = CodeReviewCommit.newRevWalk(subrepo)) { Ref ref = subrepo.getRefDatabase().exactRef(s.getSubmodule().get()); if (ref == null) { ed.add(new DeletePath(s.getPath())); continue; } final ObjectId updateTo = ref.getObjectId(); RevCommit newCommit = rw.parseCommit(updateTo); if (author == null) { author = newCommit.getAuthorIdent(); } else if (!author.equals(newCommit.getAuthorIdent())) { sameAuthorForAll = false; } DirCacheEntry dce = dc.getEntry(s.getPath()); ObjectId oldId = null; if (dce != null) { if (!dce.getFileMode().equals(FileMode.GITLINK)) { log.error( "Requested to update gitlink " + s.getPath() + " in " + s.getSubmodule().getParentKey().get() + " but entry " + "doesn't have gitlink file mode."); continue; } oldId = dce.getObjectId(); } else { // This submodule did not exist before. We do not want to add // the full submodule history to the commit message, so omit it. oldId = updateTo; } ed.add( new PathEdit(s.getPath()) { @Override public void apply(DirCacheEntry ent) { ent.setFileMode(FileMode.GITLINK); ent.setObjectId(updateTo); } }); if (verboseSuperProject) { msgbuf.append("Project: " + s.getSubmodule().getParentKey().get()); msgbuf.append(" " + s.getSubmodule().getShortName()); msgbuf.append(" " + updateTo.getName()); msgbuf.append("\n\n"); try { rw.markStart(newCommit); if (oldId != null) { rw.markUninteresting(rw.parseCommit(oldId)); } for (RevCommit c : rw) { msgbuf.append(c.getFullMessage() + "\n\n"); } } catch (IOException e) { logAndThrowSubmoduleException( "Could not perform a revwalk to " + "create superproject commit message", e); } } } } ed.finish(); if (!sameAuthorForAll || author == null) { author = myIdent; } ObjectInserter oi = pdb.newObjectInserter(); ObjectId tree = dc.writeTree(oi); ObjectId currentCommitId = pdb.getRef(subscriber.get()).getObjectId(); CommitBuilder commit = new CommitBuilder(); commit.setTreeId(tree); commit.setParentIds(new ObjectId[] {currentCommitId}); commit.setAuthor(author); commit.setCommitter(myIdent); commit.setMessage(msgbuf.toString()); oi.insert(commit); oi.flush(); ObjectId commitId = oi.idFor(Constants.OBJ_COMMIT, commit.build()); final RefUpdate rfu = pdb.updateRef(subscriber.get()); rfu.setForceUpdate(false); rfu.setNewObjectId(commitId); rfu.setExpectedOldObjectId(currentCommitId); rfu.setRefLogMessage("Submit to " + subscriber.getParentKey().get(), true); switch (rfu.update()) { case NEW: case FAST_FORWARD: gitRefUpdated.fire(subscriber.getParentKey(), rfu); changeHooks.doRefUpdatedHook(subscriber, rfu, account); // TODO since this is performed "in the background" no mail will be // sent to inform users about the updated branch break; default: throw new IOException(rfu.getResult().name()); } recRw = new RevWalk(pdb); // Recursive call: update subscribers of the subscriber updateSuperProjects(db, Sets.newHashSet(subscriber)); } catch (IOException e) { throw new SubmoduleException("Cannot update gitlinks for " + subscriber.get(), e); } finally { if (recRw != null) { recRw.close(); } if (pdb != null) { pdb.close(); } } }
@Override @Before public void setUp() throws Exception { super.setUp(); // create Main Git Repository workdir = new File("D://Repository1"); if (workdir.exists()) { FileUtils.delete(workdir, FileUtils.RECURSIVE | FileUtils.RETRY); } FileUtils.mkdir(workdir, true); // init RepositoryUtil class repositoryUtil = new RepositoryUtil(new File(workdir, Constants.DOT_GIT)); repository1 = repositoryUtil.getRepository(); // create file, add and commit File file = new File(workdir, "file.txt"); FileUtils.createNewFile(file); repositoryUtil.appendFileContent(file, "Contect file"); Git git = new Git(repository1); git.add().addFilepattern("file.txt").call(); git.commit().setMessage("First Commit").call(); // clone Git Repository 2 workdir2 = new File("D:/Repository2"); if (workdir2.exists()) { FileUtils.delete(workdir2, FileUtils.RECURSIVE | FileUtils.RETRY); } FileUtils.mkdir(workdir2, true); URIish uri = new URIish("file:///" + repository1.getDirectory().toString()); CloneOperation clop = new CloneOperation( uri.toString(), true, null, workdir2, "refs/heads/master", "origin", 0, null, null); clop.execute(); repository2 = new FileRepository(new File(workdir2, Constants.DOT_GIT)); // clone Git Repository 3 workdir3 = new File("D:/Repository3"); if (workdir3.exists()) { FileUtils.delete(workdir3, FileUtils.RECURSIVE | FileUtils.RETRY); } FileUtils.mkdir(workdir3, true); uri = new URIish("file:///" + repository1.getDirectory().toString()); clop = new CloneOperation( uri.toString(), true, null, workdir3, "refs/heads/master", "origin", 0, null, null); clop.execute(); repository3 = new FileRepository(new File(workdir3, Constants.DOT_GIT)); RefUpdate createBranch = repository2.updateRef("refs/heads/test"); createBranch.setNewObjectId(repository2.resolve("refs/heads/master")); createBranch.update(); }
private RefUpdate updateBranch(Branch.NameKey destBranch, IdentifiedUser caller) throws IntegrationException { RefUpdate branchUpdate = getPendingRefUpdate(destBranch); CodeReviewCommit branchTip = getBranchTip(destBranch); MergeTip mergeTip = mergeTips.get(destBranch); CodeReviewCommit currentTip = mergeTip != null ? mergeTip.getCurrentTip() : null; if (Objects.equals(branchTip, currentTip)) { if (currentTip != null) { logDebug("Branch already at merge tip {}, no update to perform", currentTip.name()); } else { logDebug("Both branch and merge tip are nonexistent, no update"); } return null; } else if (currentTip == null) { logDebug("No merge tip, no update to perform"); return null; } if (RefNames.REFS_CONFIG.equals(branchUpdate.getName())) { logDebug("Loading new configuration from {}", RefNames.REFS_CONFIG); try { ProjectConfig cfg = new ProjectConfig(destProject.getProject().getNameKey()); cfg.load(repo, currentTip); } catch (Exception e) { throw new IntegrationException( "Submit would store invalid" + " project configuration " + currentTip.name() + " for " + destProject.getProject().getName(), e); } } branchUpdate.setRefLogIdent( identifiedUserFactory.create(caller.getAccountId()).newRefLogIdent()); branchUpdate.setForceUpdate(false); branchUpdate.setNewObjectId(currentTip); branchUpdate.setRefLogMessage("merged", true); try { RefUpdate.Result result = branchUpdate.update(rw); logDebug( "Update of {}: {}..{} returned status {}", branchUpdate.getName(), branchUpdate.getOldObjectId(), branchUpdate.getNewObjectId(), result); switch (result) { case NEW: case FAST_FORWARD: if (branchUpdate.getResult() == RefUpdate.Result.FAST_FORWARD) { tagCache.updateFastForward( destBranch.getParentKey(), branchUpdate.getName(), branchUpdate.getOldObjectId(), currentTip); } if (RefNames.REFS_CONFIG.equals(branchUpdate.getName())) { Project p = destProject.getProject(); projectCache.evict(p); destProject = projectCache.get(p.getNameKey()); repoManager.setProjectDescription(p.getNameKey(), p.getDescription()); } return branchUpdate; case LOCK_FAILURE: throw new IntegrationException("Failed to lock " + branchUpdate.getName()); default: throw new IOException(branchUpdate.getResult().name() + '\n' + branchUpdate); } } catch (IOException e) { throw new IntegrationException("Cannot update " + branchUpdate.getName(), e); } }
/** * Execute the SubmoduleUpdateCommand command. * * @return a collection of updated submodule paths * @throws ConcurrentRefUpdateException * @throws CheckoutConflictException * @throws InvalidMergeHeadsException * @throws InvalidConfigurationException * @throws NoHeadException * @throws NoMessageException * @throws RefNotFoundException * @throws WrongRepositoryStateException * @throws GitAPIException */ public Collection<String> call() throws InvalidConfigurationException, NoHeadException, ConcurrentRefUpdateException, CheckoutConflictException, InvalidMergeHeadsException, WrongRepositoryStateException, NoMessageException, NoHeadException, RefNotFoundException, GitAPIException { checkCallable(); try { SubmoduleWalk generator = SubmoduleWalk.forIndex(repo); if (!paths.isEmpty()) generator.setFilter(PathFilterGroup.createFromStrings(paths)); List<String> updated = new ArrayList<String>(); while (generator.next()) { // Skip submodules not registered in .gitmodules file if (generator.getModulesPath() == null) continue; // Skip submodules not registered in parent repository's config String url = generator.getConfigUrl(); if (url == null) continue; Repository submoduleRepo = generator.getRepository(); // Clone repository is not present if (submoduleRepo == null) { CloneCommand clone = Git.cloneRepository(); configure(clone); clone.setURI(url); clone.setDirectory(generator.getDirectory()); clone.setGitDir( new File(new File(repo.getDirectory(), Constants.MODULES), generator.getPath())); if (monitor != null) clone.setProgressMonitor(monitor); submoduleRepo = clone.call().getRepository(); } try { RevWalk walk = new RevWalk(submoduleRepo); RevCommit commit = walk.parseCommit(generator.getObjectId()); String update = generator.getConfigUpdate(); if (ConfigConstants.CONFIG_KEY_MERGE.equals(update)) { MergeCommand merge = new MergeCommand(submoduleRepo); merge.include(commit); merge.setStrategy(strategy); merge.call(); } else if (ConfigConstants.CONFIG_KEY_REBASE.equals(update)) { RebaseCommand rebase = new RebaseCommand(submoduleRepo); rebase.setUpstream(commit); rebase.setStrategy(strategy); rebase.call(); } else { // Checkout commit referenced in parent repository's // index as a detached HEAD DirCacheCheckout co = new DirCacheCheckout(submoduleRepo, submoduleRepo.lockDirCache(), commit.getTree()); co.setFailOnConflict(true); co.checkout(); RefUpdate refUpdate = submoduleRepo.updateRef(Constants.HEAD, true); refUpdate.setNewObjectId(commit); refUpdate.forceUpdate(); } } finally { submoduleRepo.close(); } updated.add(generator.getPath()); } return updated; } catch (IOException e) { throw new JGitInternalException(e.getMessage(), e); } catch (ConfigInvalidException e) { throw new InvalidConfigurationException(e.getMessage(), e); } }