Greasy Fork is available in English.

Github manual merge

Fixes the manual merge instructions on github

// ==UserScript==
// @name         Github manual merge
// @namespace    https://github.com/lordwelch/
// @version      2.3
// @description  Fixes the manual merge instructions on github
// @license      MIT
// @author       lordwelch
// @match        https://github.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=github.com
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(async function() {
    'use strict';
    console.log("script started");
    var pushState = history.pushState;
    var replaceState = history.replaceState;

    history.pushState = function() {
        pushState.apply(history, arguments);
        window.dispatchEvent(new Event('pushstate'));
        window.dispatchEvent(new Event('locationchange'));
    };

    history.replaceState = function() {
        replaceState.apply(history, arguments);
        window.dispatchEvent(new Event('replacestate'));
        window.dispatchEvent(new Event('locationchange'));
    };

    window.addEventListener('popstate', function() {
        window.dispatchEvent(new Event('locationchange'));
    });
    window.addEventListener("load", function() {
        window.dispatchEvent(new Event('locationchange'));
    });
    function breakCheck() {
        if (document.getElementById('gh-manual-pull-fix') != null) {
            console.log("fix is already applied");
            return;
        }
        if (document.getElementById('gh-manual-merge-fix') != null) {
            console.log("fix is already applied");
            return;
        }
        var location = document.location.pathname.match(/\/([^/]+)\/([^/]+)\/pull\/(\d+)$/);
        if (location == null) {
            console.log("incorrect page");
            return;
        }
    }

    function trimSuffix(str, suffix) {
        if (str.endsWith(suffix)) {
            return str.substr(0, str.length-suffix.length);
        }
        return str;
    }
    function trimPrefix(str, prefix) {
        if (str.startsWith(prefix)) {
            return str.substr(prefix.length-str.length);
        }
        return str;
    }

    function FixForkInstructions(argument) {
        if (breakCheck()) {
            return;
        }

        var urlObj = document.getElementById("clone-help-git-url");
        var url = trimSuffix(urlObj.value.trim(), ".git");
        var stepInstructions = document.querySelectorAll('p.step');
        var step1 = document.querySelector("#clone-help-step-1");
        var step2 = document.querySelector("#clone-help-step-2");

        var primaryBranch = step1.textContent.trim().split("\n").at(0).split(" ").at(-1);
        var branchName = step1.textContent.trim().split(" ").at(-1);
        var repoOwner = url.split("/").at(-2);

        if (primaryBranch.indexOf("/") >= 0 || branchName.indexOf("/") >= 0 || repoOwner.indexOf("/") >= 0) {
            return
        }

        var pullInstructions = `git stash\ngit checkout ${primaryBranch}\ngit fetch --force ${url} +${branchName}:${repoOwner}/${branchName}\ngit checkout ${repoOwner}/${branchName}`;
        var mergeInstructions = `git checkout ${primaryBranch}\ngit merge ${repoOwner}/${branchName}`;

        var spPull = document.createElement("span");
        spPull.id = 'gh-manual-pull-fix';
        spPull.textContent = pullInstructions;

        var spMerge = document.createElement("span");
        spMerge.id = 'gh-manual-merge-fix';
        spMerge.textContent = mergeInstructions;
        if (breakCheck()) {
            return;
        }

        var parent = step1.parentNode.parentNode;
        step1.textContent = '';
        step2.textContent = '';
        for (let i = 0; i < stepInstructions.length; i++) {
          stepInstructions[i].textContent = "";
        }

        if (breakCheck()) {
            return;
        }
        step1.appendChild(spPull);

        var str = document.createElement("strong");
        str.textContent = "Pull Instructions:"
        stepInstructions[0].appendChild(str);
        stepInstructions[0].appendChild(document.createTextNode(" Stash your changes. Checkout the primary branch. Force fetch the pr branch. Checkout the pr branch."));

        step2.appendChild(spMerge);

        var str = document.createElement("strong");
        str.textContent = "Merge Instructions:"
        stepInstructions[1].appendChild(str);
        stepInstructions[1].appendChild(document.createTextNode(" Checkout the primary branch. Merge the pr branch."));
    }

    function FixBranchInstructions(argument) {
        if (breakCheck()) {
            return;
        }

        var urlObj = document.getElementById("clone-help-git-url");
        var url = trimSuffix(urlObj.value.trim(), ".git");
        var stepInstructions = document.querySelectorAll('p.step');
        var step1 = document.querySelector("#clone-help-step-1");
        var step2 = document.querySelector("#clone-help-step-2");
        var step3 = document.querySelector("#clone-help-step-3");
        var step4 = document.querySelector("#clone-help-step-4");

        var primaryBranch = step1.textContent.trim().split(" ").at(-1);
        var branchName = step3.textContent.trim().split(" ").at(-1);
        var repoOwner = url.split("/").at(-2);

        if (primaryBranch.indexOf("/") >= 0 || branchName.indexOf("/") >= 0 || repoOwner.indexOf("/") >= 0) {
            return
        }

        var pullInstructions = `git stash\ngit checkout ${primaryBranch}\ngit fetch --force ${url} +${branchName}:${branchName}\ngit checkout ${branchName}`;
        var mergeInstructions = `git checkout ${primaryBranch}\ngit merge ${branchName}`;

        var spPull = document.createElement("span");
        spPull.id = 'gh-manual-pull-fix';
        spPull.textContent = pullInstructions;

        var spMerge = document.createElement("span");
        spMerge.id = 'gh-manual-merge-fix';
        spMerge.textContent = mergeInstructions;
        if (breakCheck()) {
            return;
        }

        var parent = step1.parentNode.parentNode;
        step1.textContent = '';
        step2.textContent = '';
        parent.removeChild(step3.parentNode);
        parent.removeChild(step4.parentNode);
        for (let i = 0; i < stepInstructions.length; i++) {
          stepInstructions[i].textContent = "";
        }

        step1.appendChild(spPull);

        var str = document.createElement("strong");
        str.textContent = "Pull Instructions:"
        stepInstructions[0].appendChild(str);
        stepInstructions[0].appendChild(document.createTextNode(" Stash your changes. Checkout the primary branch. Force fetch the pr branch. Checkout the pr branch."));

        step2.appendChild(spMerge);

        var str = document.createElement("strong");
        str.textContent = "Merge Instructions:"
        stepInstructions[1].appendChild(str);
        stepInstructions[1].appendChild(document.createTextNode(" Checkout the primary branch. Merge the pr branch."));
    }
    async function fixManualMergeInstructions() {
        console.log("script running");
        if (breakCheck()) {
            return;
        }
        var location = document.location.pathname.match(/\/([^/]+)\/([^/]+)\/pull\/(\d+)$/);
        if (location == null) {
            return;
        }
        var upstreamOwner = location[1];
        var upstreamRepo = location[2];
        var upstreamPrNum = location[3];
        var urlObj = document.getElementById("clone-help-git-url");
        while (urlObj == null) {
            await new Promise(r => setTimeout(r, 300));
            console.log("Waiting for pr to load");
            if (breakCheck()) {
                return;
            }
            location = document.location.pathname.match(/\/([^/]+)\/([^/]+)\/pull\/(\d+)$/);
            if (location == null) {
                continue;
            }
            upstreamOwner = location[1];
            upstreamRepo = location[2];
            upstreamPrNum = location[3];
            urlObj = document.getElementById("clone-help-git-url");
        }
        if (breakCheck()) {
            return;
        }
        var prPath = trimSuffix(trimPrefix(urlObj.value, "https://github.com"), ".git");
        var prLocation = prPath.match(/\/([^/]+)\/([^/]+)$/);
        var downstreamOwner = prLocation[1];
        var downstreamRepo = prLocation[2];

        if (downstreamRepo != upstreamRepo || downstreamOwner != upstreamOwner) {
            FixForkInstructions()
        } else {
            FixBranchInstructions()
        }
    }
    window.addEventListener('locationchange', fixManualMergeInstructions);
    fixManualMergeInstructions();
})();