Merge pull request #33771 from overleaf/mj-git-bridge-default-main

[git-bridge] Default new projects to main rather than master

GitOrigin-RevId: 3d7d60c0aab6e5d0d10d282d6d491d4f735ed94c
This commit is contained in:
David
2026-06-12 08:06:20 +00:00
committed by Copybot
parent 886985d91c
commit f27112179a
10 changed files with 191 additions and 5 deletions
@@ -14,6 +14,7 @@ import org.apache.commons.io.IOUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ResetCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
@@ -83,6 +84,8 @@ public class GitProjectRepo implements ProjectRepo {
return;
}
repo.create();
// Set default branch to "main" for new projects
repo.updateRef(Constants.HEAD).link("refs/heads/main");
}
@Override
@@ -449,6 +449,17 @@ public class WLGitBridgeIntegrationTest {
.build());
}
});
put(
"masterBranchSurvivesSwap",
new HashMap<String, SnapshotAPIState>() {
{
put(
"state",
new SnapshotAPIStateBuilder(
getResourceAsStream("/masterBranchSurvivesSwap/state/state.json"))
.build());
}
});
}
};
@@ -522,6 +533,13 @@ public class WLGitBridgeIntegrationTest {
assertEquals(0, runtime.exec("git pull", null, dir).waitFor());
}
private String gitBranch(File dir) throws IOException, InterruptedException {
Process proc =
runtime.exec(new String[] {"git", "rev-parse", "--abbrev-ref", "HEAD"}, null, dir);
assertEquals(0, proc.waitFor());
return IOUtils.toString(proc.getInputStream(), StandardCharsets.UTF_8).trim();
}
@Test
public void canCloneARepository() throws IOException, GitAPIException, InterruptedException {
server = new MockSnapshotServer(3857, getResource("/canCloneARepository").toFile());
@@ -807,7 +825,7 @@ public class WLGitBridgeIntegrationTest {
"remote: hint: hello world.png (rename to: hello_world.png)",
"remote: hint: an image.jpg (rename to: an_image.jpg)",
"To " + gitRemoteUrl(port),
"! [remote rejected] master -> master (invalid files)",
"! [remote rejected] main -> main (invalid files)",
"error: failed to push some refs to '" + gitRemoteUrl(port) + "'");
}
@@ -835,7 +853,7 @@ public class WLGitBridgeIntegrationTest {
"remote: hint: project: no main file",
"remote: hint: The project would have no (editable) main .tex file.",
"To " + gitRemoteUrl(port),
"! [remote rejected] master -> master (invalid project)",
"! [remote rejected] main -> main (invalid project)",
"error: failed to push some refs to '" + gitRemoteUrl(port) + "'");
}
@@ -864,7 +882,7 @@ public class WLGitBridgeIntegrationTest {
"remote: hint: There was an internal error with the Overleaf server.",
"remote: hint: Please contact Overleaf.",
"To " + gitRemoteUrl(port),
"! [remote rejected] master -> master (Overleaf error)",
"! [remote rejected] main -> main (Overleaf error)",
"error: failed to push some refs to '" + gitRemoteUrl(port) + "'");
}
@@ -896,7 +914,7 @@ public class WLGitBridgeIntegrationTest {
"remote: hint: You have 1 invalid files in your Overleaf project:",
"remote: hint: file1.exe (invalid file extension)",
"To " + gitRemoteUrl(port),
"! [remote rejected] master -> master (invalid files)",
"! [remote rejected] main -> main (invalid files)",
"error: failed to push some refs to '" + gitRemoteUrl(port) + "'");
}
@@ -1012,13 +1030,59 @@ public class WLGitBridgeIntegrationTest {
assertFalse(testProj2ServerDir.exists());
}
@Test
public void masterBranchSurvivesSwap() throws Exception {
int mockServerPort = 4010;
server =
new MockSnapshotServer(mockServerPort, getResource("/masterBranchSurvivesSwap").toFile());
server.start();
server.setState(states.get("masterBranchSurvivesSwap").get("state"));
wlgb =
new GitBridgeApp(
new String[] {
makeConfigFile(0, mockServerPort, new SwapJobConfig(1, 0, 0, 250, null, true))
});
wlgb.run();
File rootGitDir = new File(wlgb.config.getRootGitDirectory());
File proj1ServerDir = new File(rootGitDir, PROJECT_ID1);
File proj2ServerDir = new File(rootGitDir, PROJECT_ID2);
// Clone project 1 — created with default branch "main"
File proj1Dir = gitClone(PROJECT_ID1, wlgb.getPort(), dir);
assertEquals("main", gitBranch(proj1Dir));
assertTrue(proj1ServerDir.exists());
// Simulate a legacy repo: rewrite server-side HEAD to master
assertEquals(
0,
runtime
.exec(new String[] {"git", "branch", "-m", "main", "master"}, null, proj1ServerDir)
.waitFor());
// Clone project 2 — triggers eviction of project 1
gitClone(PROJECT_ID2, wlgb.getPort(), dir);
while (proj1ServerDir.exists())
;
assertFalse(proj1ServerDir.exists());
assertTrue(proj2ServerDir.exists());
// Re-clone project 1 — triggers restore from swap
FileUtils.deleteDirectory(proj1Dir);
File proj1DirRestored = gitClone(PROJECT_ID1, wlgb.getPort(), dir);
while (proj2ServerDir.exists())
;
// Verify the restored repo still uses "master"
assertEquals("master", gitBranch(proj1DirRestored));
}
private static List<String> expectedPushSubmodule(int port) {
return Arrays.asList(
"remote: hint: Your Git repository contains a reference we cannot resolve.",
"remote: hint: If your project contains a Git submodule,",
"remote: hint: please remove it and try again.",
"To " + gitRemoteUrl(port),
"! [remote rejected] master -> master (invalid git repo)",
"! [remote rejected] main -> main (invalid git repo)",
"error: failed to push some refs to '" + gitRemoteUrl(port) + "'");
}
@@ -13,6 +13,7 @@ import java.nio.file.Paths;
import java.util.*;
import java.util.function.Supplier;
import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.lib.Constants;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -169,4 +170,28 @@ public class GitProjectRepoTest {
withoutIncoming.deleteIncomingPacks();
assertTrue(FileUtil.directoryDeepEquals(actual, expected));
}
@Test
public void initRepoSetsDefaultBranchToMain() throws IOException {
FSGitRepoStore store =
new FSGitRepoStore(tmpFolder.newFolder("newrepos").getAbsolutePath(), Optional.empty());
GitProjectRepo newRepo = GitProjectRepo.fromName("testproject");
newRepo.initRepo(store);
assertEquals("refs/heads/main", newRepo.getJGitRepository().getFullBranch());
}
@Test
public void initRepoDoesNotRewriteExistingMasterRepoToMain() throws IOException {
FSGitRepoStore store =
new FSGitRepoStore(tmpFolder.newFolder("legacyrepos").getAbsolutePath(), Optional.empty());
GitProjectRepo newRepo = GitProjectRepo.fromName("testproject");
newRepo.initRepo(store);
newRepo.getJGitRepository().updateRef(Constants.HEAD).link("refs/heads/master");
assertEquals("refs/heads/master", newRepo.getJGitRepository().getFullBranch());
GitProjectRepo existingRepo = GitProjectRepo.fromName("testproject");
existingRepo.initRepo(store);
assertEquals("refs/heads/master", existingRepo.getJGitRepository().getFullBranch());
}
}
@@ -0,0 +1,90 @@
[
{
"project": "111111111111111111111111",
"getDoc": {
"versionID": 1,
"createdAt": "2014-11-30T18:40:58.123Z",
"email": "jdleesmiller+1@gmail.com",
"name": "John+1"
},
"getSavedVers": [
{
"versionID": 1,
"comment": "added more info on doc GET and error details\n",
"email": "jdleesmiller+1@gmail.com",
"name": "John+1",
"createdAt": "2014-11-30T18:47:01.456Z"
}
],
"getForVers": [
{
"versionID": 1,
"srcs": [
{
"content": "content\n",
"path": "main.tex"
},
{
"content": "This text is from another file.",
"path": "foo/bar/test.tex"
}
],
"atts": [
{
"url": "http://127.0.0.1:4010/state/111111111111111111111111/overleaf-white-410.png",
"path": "overleaf-white-410.png"
}
]
}
],
"push": "success",
"postback": {
"type": "success",
"versionID": 2
}
},
{
"project": "222222222222222222222222",
"getDoc": {
"versionID": 1,
"createdAt": "2014-11-30T18:40:58.123Z",
"email": "jdleesmiller+1@gmail.com",
"name": "John+1"
},
"getSavedVers": [
{
"versionID": 1,
"comment": "added more info on doc GET and error details",
"email": "jdleesmiller+1@gmail.com",
"name": "John+1",
"createdAt": "2014-11-30T18:47:01.456Z"
}
],
"getForVers": [
{
"versionID": 1,
"srcs": [
{
"content": "different content\n",
"path": "main.tex"
},
{
"content": "a different one",
"path": "foo/bar/test.tex"
}
],
"atts": [
{
"url": "http://127.0.0.1:4010/state/222222222222222222222222/editor-versions-a7e4de19d015c3e7477e3f7eaa6c418e.png",
"path": "editor-versions-a7e4de19d015c3e7477e3f7eaa6c418e.png"
}
]
}
],
"push": "success",
"postback": {
"type": "success",
"versionID": 2
}
}
]