From f27112179abbe5e0d11c021ed0f73dc8b91bc7f7 Mon Sep 17 00:00:00 2001 From: David <33458145+davidmcpowell@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:17:12 +0100 Subject: [PATCH] Merge pull request #33771 from overleaf/mj-git-bridge-default-main [git-bridge] Default new projects to main rather than master GitOrigin-RevId: 3d7d60c0aab6e5d0d10d282d6d491d4f735ed94c --- .../bridge/repo/GitProjectRepo.java | 3 + .../WLGitBridgeIntegrationTest.java | 74 +++++++++++++- .../bridge/repo/GitProjectRepoTest.java | 25 +++++ .../111111111111111111111111/foo/bar/test.tex | 1 + .../state/111111111111111111111111/main.tex | 1 + .../overleaf-white-410.png | Bin 0 -> 8786 bytes ...sions-a7e4de19d015c3e7477e3f7eaa6c418e.png | Bin 0 -> 3573 bytes .../222222222222222222222222/foo/bar/test.tex | 1 + .../state/222222222222222222222222/main.tex | 1 + .../masterBranchSurvivesSwap/state/state.json | 90 ++++++++++++++++++ 10 files changed, 191 insertions(+), 5 deletions(-) create mode 100644 services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/111111111111111111111111/foo/bar/test.tex create mode 100644 services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/111111111111111111111111/main.tex create mode 100644 services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/111111111111111111111111/overleaf-white-410.png create mode 100644 services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/222222222222222222222222/editor-versions-a7e4de19d015c3e7477e3f7eaa6c418e.png create mode 100644 services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/222222222222222222222222/foo/bar/test.tex create mode 100644 services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/222222222222222222222222/main.tex create mode 100644 services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/state.json diff --git a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/GitProjectRepo.java b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/GitProjectRepo.java index 54c5a57b86..d9d190883c 100644 --- a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/GitProjectRepo.java +++ b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/GitProjectRepo.java @@ -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 diff --git a/services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/application/WLGitBridgeIntegrationTest.java b/services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/application/WLGitBridgeIntegrationTest.java index e017476ca9..f3eb95b693 100644 --- a/services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/application/WLGitBridgeIntegrationTest.java +++ b/services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/application/WLGitBridgeIntegrationTest.java @@ -449,6 +449,17 @@ public class WLGitBridgeIntegrationTest { .build()); } }); + put( + "masterBranchSurvivesSwap", + new HashMap() { + { + 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 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) + "'"); } diff --git a/services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/bridge/repo/GitProjectRepoTest.java b/services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/bridge/repo/GitProjectRepoTest.java index 7222203223..480792b736 100644 --- a/services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/bridge/repo/GitProjectRepoTest.java +++ b/services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/bridge/repo/GitProjectRepoTest.java @@ -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()); + } } diff --git a/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/111111111111111111111111/foo/bar/test.tex b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/111111111111111111111111/foo/bar/test.tex new file mode 100644 index 0000000000..046794f19a --- /dev/null +++ b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/111111111111111111111111/foo/bar/test.tex @@ -0,0 +1 @@ +This text is from another file. \ No newline at end of file diff --git a/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/111111111111111111111111/main.tex b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/111111111111111111111111/main.tex new file mode 100644 index 0000000000..d95f3ad14d --- /dev/null +++ b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/111111111111111111111111/main.tex @@ -0,0 +1 @@ +content diff --git a/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/111111111111111111111111/overleaf-white-410.png b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/111111111111111111111111/overleaf-white-410.png new file mode 100644 index 0000000000000000000000000000000000000000..6a23d10c15d3eb7fcb18609be0bc4bf0706eca49 GIT binary patch literal 8786 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 literal 0 HcmV?d00001 diff --git a/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/222222222222222222222222/editor-versions-a7e4de19d015c3e7477e3f7eaa6c418e.png b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/222222222222222222222222/editor-versions-a7e4de19d015c3e7477e3f7eaa6c418e.png new file mode 100644 index 0000000000000000000000000000000000000000..7fa339be7a9ab251a9d2adde54b39501bc0dc056 GIT binary patch literal 3573 zcmVVGd000McNliru-3u8IH87xi-9G>T4T4ET zK~#9!?Okh(Rn-;#*1iKch#-iFiq=O3As~q;iVE0JAE=*Hk9=&dk~8dGDN+%%7P# zcdxa+Z?C=fKKrf(6jDebg%r|3#p>NalDh-w2VgemJ$(52eDIM7+X)VdWlAKsXfb>K9g=TgZfZ+gk&52rzCCxUoyUpzVVrs@a%R7-A zO7eb^%Da$!Q_^^ny$kfB&-QCn!$R^el6n+NKzQIEHnZ^ndelP@127-J_swi^-js7W z0==K4DI{fP=hO-KUrw?S0N#=`o8;&s0_+TY1AvRnY+47(Yo0f=v&?K=hb92YVF2cs zS@#Z@;_Q%glXLEt4o3h(4-U_z1VVu_>+opUdD2m+8C1>kRHRzSb=q`1*JcXM46 zfaDZ2yEG*^X+qRH=C+(Lq<(E*8OIn-oN#a8_3qHw< z5_HUZlHViQHDen)m&x!_lJ6F35&T;da>jEckI19VK@jwn^wWgwULdJct$=?|0uFdl z(tsM808=Ebi`fV7O6t;~Wr?J@c2!8~pC2FHZ`c9Iv=`EhS=k}F~&!R>i5>a!S( z*+Q}pI*5>bAf`!kbk>Hv9Rv8YNxF>mA4u|IlH*8rNqOwE;$T1!1bdaQ#i#DP>tX=^ z4;ca9o8+q%^!Y)`dYl#m2Nq`Gz)>-P|MQH%FOh6&MXy^^*5{z|cMYQW^8T7y_eoxy zVa{@G8|pQsosW?0BWX)SpME1PWuJ(s=x;L4TjsPw$0IV(Ygk0TZU};)A!#KKloZt3 zn%}~PFWRB%`5EaJb!q)!(h9DL0RBScKuES{y`7Yyeq$m=f~Rs0{EWt zUE;e0TFaAYED5%RW>q=9V_U`SX3z~gALkXRDIFVI})Fif=Gv#lg>s7C}S2$0<}5W2oF z$-`R90Yca4FO^E03n(%ZpZ5ZXR3v~;8M1O!&O&O40Fw5uMgX6izaJJDWO^2`+T*dF z6$xNwKIPbo^*>tztn_%STeTdZZ%PUjlCA87bHi7bfW5+A0WY^zt(I+`WM&fq>|0^K zDgbLF&2r97@4#97WB_9T>|W(xmP&fiIrmyC9}^(l+uOY=62QzFJR-o3D&S8vvl;Dp zeiF%}opY%)kqCmI6A~`<9%4H-1Hi;~_~=rSBb{^A`Uh-9hz_bPagJJ@tJ+D_ogoxD zn`A15A)Rwe^U$h>WP_QV8sd?gTKQXJ$f&cu8UcLP^8>2OC_H5)Av@&1`81@FD5dgtPYmzy~4z z|A82X|F~KbxWOYlR_ph7xuk>4?D#g8k0oX{JmIka4uE|^JhH(v8ipYNB@L1EmYMZy zEdok<(mD6*Du3J0WB8R73E-St@9|;%t2mtiPA1vS%sN%b6--i-b8ch8S@!af;6u_- z=iF8#EM~S9z#$~Nn^~!nk4SDSl}cM$(Y0sTNo!_ns_g={mb+|)`LJPa%)U)oBw0Za z?B<+%*8}`BoO2(fsjG8tLxji2cs#SdY620K0027Yt)W8@1dX2Hk9E#HU1LWHJ_Puz zwQTv-u(gUw?wzy46`!wBA6bhBNhCv87j1P5VP;{=kr;B)=AC3i$gSR&ggME~UaK|m zgCJ-uH@ggD>!)q)Azu%l%hlOC=#LV7ol>n0d>k)D@ zt)?N#oO5r7T=OYulymMW)UNFBaR{`a zdrX$a?fEC4IyA%6c0dpW-6XB>&~-fOKuB)&u>GjEasWv3sqb@Q%HZ!>u09%et9Pn% z?wL9OzrUGv@rVHbX;)(85d;>byzZ~)C|kWM1h~Ot_P^iW58vIVzg-Xny;3mT`Rwya zjzJxXq&Gc$a9(>qyuqg}I>`r;G&%@^9-eFd#CigsWN(k?w}WK&FoQhpG02*vI$W1$ zzE9Zy7V1n$KIGwtPeWlN=_t?Lz`%q;p3m{_Y4rxaq|TnvdAiSF>pTYfDCV%=)idm$ zi#imNr+ZG!0X_t{*K@Fu8SnGYsZ;Qcqz@#ke8bIPPXfFUQ@Hb4^G`*cif@N@lD~>F z=o_Ac9vuOAlk_i-F~5yE7N5%PBt^1EltEAQB*5Dd2r$B9yz}cE{F^=dM@6gNQeKDY zIrt<`W2bfGeSQUhG)Vfwb0Q9ktbnB3JPELkWKR!+pDot>o&2%T6a4tTxa-?2+NV`4 z$;&!&w%@`RBO~+<92KV`zlfm7xgp2erL9id^}5e*dF1Q4?USS>Nhq`-LQC6TA;%hD zt+jicVV~r1lG91vB5Aig5kS)4BTTxHNf2Oi1OhDgoB{We{G{Bp`Yw`vVzlS#7Eaqn zvTIIe|9ugB{X~+i+!}$EGjkMPOOjSs&~aK0bQ>3?dw3882Pa8@fe~Aq-<}f!be2?U zNqa71y^hVje@V`WsN`)qCO~F&kAomMSkdGQlHJluP(FxAg6j$b?Bvg0BsWF$=?I^( zou|TQM={vUeo68g6atb%B(3$V()J}D(^9|YF6oAdAxk9h?8p(o=e>vbWzPhh=tzDP zg8|QXL;{e!Krsl({i5jMT_nmmM>9K6()uV0nAr)E7Pr;pIEe{Z373?>pK4~mjUj?e zaLz5udJX$}OiY%fv1vswNlPo}aDBq#_LB5YO#XTRd6B4x7cC4+WiKvi=vU9$lU_^9 z_xV_N;D5!yOBA21COJ6;o%bayLM;l(A1h%YIZM*9B=;n()<9;q#LSKaa3O&01=c&sHUQV94SuQ-phYz3 z1>jErMiBxV$K0W-HCCkEDYEOsyx>C4CIwdH{`i z0zX#~pn}sHC0%J|lK|A>8^P_8o&s>Ub8c>t>qZcgN0D5V;CXvo(nN9<$;%4Vk|9D5 zNhgt+=2jJ