From cf4ef83e164ccfc5b8587a937440a4248af07ed4 Mon Sep 17 00:00:00 2001 From: Ignas Mikalajunas Date: Thu, 15 Aug 2024 23:12:33 +0300 Subject: [PATCH] Fix symbolic ref handling by the ref database, also set up HEAD symbolic ref on the first repo push --- .../lt/pow/nukagit/dfs/GitDfsPackCommand.java | 19 +++++++++++++++++++ .../pow/nukagit/dfs/NukagitDfsRepository.java | 8 +++++--- .../integration/NukagitIntegrationTest.groovy | 9 ++++----- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/main/java/lt/pow/nukagit/dfs/GitDfsPackCommand.java b/src/main/java/lt/pow/nukagit/dfs/GitDfsPackCommand.java index abfacdf..56f3965 100644 --- a/src/main/java/lt/pow/nukagit/dfs/GitDfsPackCommand.java +++ b/src/main/java/lt/pow/nukagit/dfs/GitDfsPackCommand.java @@ -5,6 +5,8 @@ import org.apache.sshd.common.util.threads.CloseableExecutorService; import org.apache.sshd.git.pack.GitPackCommand; import org.eclipse.jgit.internal.storage.dfs.DfsRepository; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.transport.ReceivePack; import org.eclipse.jgit.transport.RemoteConfig; @@ -54,6 +56,23 @@ public void run() { uploadPack(db); } else if (RemoteConfig.DEFAULT_RECEIVE_PACK.equals(subCommand)) { receivePack(db); + // if HEAD ref has not been set up yet, set it up + if (db.getRefDatabase().exactRef(Constants.HEAD) == null) { + List preferredRefs = List.of("main", "master"); + boolean headSet = false; + for (String ref : preferredRefs) { + if (db.getRefDatabase().exactRef(Constants.R_HEADS + ref) != null) { + RefUpdate u = db.updateRef(Constants.HEAD); + u.link(Constants.R_HEADS + ref); + headSet = true; + break; + } + } + // If no preferred refs exist, link HEAD to the only ref if there is exactly one + if (!headSet && db.getRefDatabase().getRefs().size() == 1) { + RefUpdate u = db.updateRef(Constants.HEAD); + u.link(db.getRefDatabase().getRefs().get(0).getName()); + } } } else { throw new IllegalArgumentException("Unknown git command: " + command); } diff --git a/src/main/java/lt/pow/nukagit/dfs/NukagitDfsRepository.java b/src/main/java/lt/pow/nukagit/dfs/NukagitDfsRepository.java index ebabc09..586af59 100644 --- a/src/main/java/lt/pow/nukagit/dfs/NukagitDfsRepository.java +++ b/src/main/java/lt/pow/nukagit/dfs/NukagitDfsRepository.java @@ -131,14 +131,14 @@ private Ref toJgitRef(HashMap allRefMap, DfsRef dfsRef) { } else if (dfsRef.isPeeled()) { if (dfsRef.peeledRef() == null) { return new ObjectIdRef.PeeledNonTag( - Ref.Storage.LOOSE, dfsRef.name(), ObjectId.fromString(dfsRef.objectID())); + Ref.Storage.PACKED, dfsRef.name(), ObjectId.fromString(dfsRef.objectID())); } return new ObjectIdRef.PeeledTag( - Ref.Storage.LOOSE, dfsRef.name(), ObjectId.fromString(dfsRef.objectID()), ObjectId.fromString(dfsRef.peeledRef())); + Ref.Storage.PACKED, dfsRef.name(), ObjectId.fromString(dfsRef.objectID()), ObjectId.fromString(dfsRef.peeledRef())); } return new ObjectIdRef.Unpeeled( - Ref.Storage.LOOSE, dfsRef.name(), ObjectId.fromString(dfsRef.objectID())); + Ref.Storage.PACKED, dfsRef.name(), ObjectId.fromString(dfsRef.objectID())); } private DfsRef toDfsRef(Ref ref) { @@ -147,6 +147,7 @@ private DfsRef toDfsRef(Ref ref) { .name(ref.getName()) .isSymbolic(true) .target(ref.getTarget().getName()) + .isPeeled(false) .build(); } return ImmutableDfsRef.builder() @@ -179,6 +180,7 @@ protected RefCache scanAllRefs() throws IOException { var idRefListBuilder = new RefList.Builder<>(); idRefListBuilder.addAll(idRefList.toArray(new Ref[0]), 0, idRefList.size()); + idRefListBuilder.addAll(symRefList.toArray(new Ref[0]), 0, symRefList.size()); idRefListBuilder.sort(); RefList ids = idRefListBuilder.toRefList(); diff --git a/src/test/groovy/lt/pow/nukagit/integration/NukagitIntegrationTest.groovy b/src/test/groovy/lt/pow/nukagit/integration/NukagitIntegrationTest.groovy index c02eea7..7daab5a 100644 --- a/src/test/groovy/lt/pow/nukagit/integration/NukagitIntegrationTest.groovy +++ b/src/test/groovy/lt/pow/nukagit/integration/NukagitIntegrationTest.groovy @@ -162,9 +162,7 @@ class NukagitIntegrationTest extends Specification { .setUri(new URIish("ssh://git@localhost:${sshPort}/${path}")) .call() commitRandomFile(git) - git.checkout().setName("main").call() git.push().setPushAll().call() - // This does not set HEAD, might be a bug in the server return git } @@ -174,8 +172,6 @@ class NukagitIntegrationTest extends Specification { CloneCommand cloneCommand = Git.cloneRepository() cloneCommand.setURI("ssh://git@localhost:${sshPort}/${path}") cloneCommand.setDirectory(clonePath) - // For now set it to main explicitly, because HEAD does not exist in the remote repository - cloneCommand.setBranch("main") return cloneCommand.call() } @@ -204,6 +200,8 @@ class NukagitIntegrationTest extends Specification { commitRandomFile(git) then: git.push().call().first().getRemoteUpdates().first().getStatus() == RemoteRefUpdate.Status.OK + // the remote should also get main branch set up as it's HEAD + git.lsRemote().call().find { it.getName() == "HEAD" }.target.name == "refs/heads/main" } def "test pushing conflicting changes to main should fail"() { @@ -264,7 +262,8 @@ class NukagitIntegrationTest extends Specification { } var git = cloneRepository("minio/repo") - git.lsRemote().call().size() == nThreads + 1 + // main and HEAD are two extra refs + git.lsRemote().call().size() == nThreads + 2 } def sshRun(String command) {