Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine which forks on GitHub are ahead?

Sometimes, the original GitHub repository of a piece of software I'm using, such as linkchecker, is seeing little or no development, while a lot of forks have been created (in this case: 142, at the time of writing).

For each fork, I'd like to know:

  • which branches it has with commits ahead of the original master branch

and for each such branch:

  • how many commits it is ahead of the original
  • how many commits it is behind

GitHub has a web interface for comparing forks, but I don't want to do this manually for each fork, I just want a CSV file with the results for all forks. How can this be scripted? The GitHub API can list the forks, but I can't see how to compare forks with it. Cloning every fork in turn and doing the comparison locally seems a bit crude.

like image 776
reinierpost Avatar asked Feb 25 '19 14:02

reinierpost


People also ask

How do I make sure forked repo is up to date?

Go to your fork, click on Fetch upstream and then click on Fetch and merge to directly sync your fork with its parent repo. You may also click on the Compare button to compare the changes before merging.

Can you see who forked your repo GitHub?

Clicking the number of forks shows you the full network. From there you can click "members" to see who forked the repo.

When should a fork be repossessed?

Most commonly, forks are used to either propose changes to someone else's project to which you do not have write access, or to use someone else's project as a starting point for your own idea. You can fork a repository to create a copy of the repository and make changes without affecting the upstream repository.


4 Answers

After clicking "Insights" on top and then "Forks" on the left, the following bookmarklet prints the info directly onto the web page like this:

screenshot

The code to add as a bookmarklet (or to paste into the console):

javascript:(async () => {
  /* while on the forks page, collect all the hrefs and pop off the first one (original repo) */
  const aTags = [...document.querySelectorAll('div.repo a:last-of-type')].slice(1);

  for (const aTag of aTags) {
    /* fetch the forked repo as html, search for the "This branch is [n commits ahead,] [m commits behind]", print it directly onto the web page */
    await fetch(aTag.href)
      .then(x => x.text())
      .then(html => aTag.outerHTML += `${html.match(/This branch is.*/).pop().replace('This branch is', '').replace(/([0-9]+ commits? ahead)/, '<font color="#0c0">$1</font>').replace(/([0-9]+ commits? behind)/, '<font color="red">$1</font>')}`)
      .catch(console.error);
  }
})();

You can also paste the code into the address bar, but note that some browsers delete the leading javascript: while pasting, so you'll have to type javascript: yourself. Or copy everything except the leading j, type j, and paste the rest.

It has been modified from this answer.


Bonus

The following bookmarklet also prints the links to the ZIP files:

screenshot

The code to add as a bookmarklet (or to paste into the console):

javascript:(async () => {
  /* while on the forks page, collect all the hrefs and pop off the first one (original repo) */
  const aTags = [...document.querySelectorAll('div.repo a:last-of-type')].slice(1);

  for (const aTag of aTags) {
    /* fetch the forked repo as html, search for the "This branch is [n commits ahead,] [m commits behind]", print it directly onto the web page */
    await fetch(aTag.href)
      .then(x => x.text())
      .then(html => aTag.outerHTML += `${html.match(/This branch is.*/).pop().replace('This branch is', '').replace(/([0-9]+ commits? ahead)/, '<font color="#0c0">$1</font>').replace(/([0-9]+ commits? behind)/, '<font color="red">$1</font>')}` + " <a " + `${html.match(/href="[^"]*\.zip">/).pop() + "Download ZIP</a>"}`)
      .catch(console.error);
  }
})();
like image 124
root Avatar answered Oct 12 '22 16:10

root


Had exactly the same itch and wrote a scraper that takes the info printed in the rendered HTML for forks: https://github.com/hbbio/forkizard

Definitely not perfect, but a temporary solution.

like image 44
Henri Avatar answered Oct 12 '22 16:10

Henri


useful-forks

useful-forks is an online tool which filters all the forks based on ahead criteria. I think it answers your needs quite well. :)

For the repo in your question, you could do: https://useful-forks.github.io/?repo=wummel/linkchecker

That should provide you with similar results to (ran on 2022-04-02): enter image description here

Also available as a Chrome plugin

You can check out the GitHub repo if you want to use it as a Chrome plugin, too: https://github.com/useful-forks/useful-forks.github.io#chrome-extension-wip

Disclaimer

I am the maintainer of this project.

like image 13
payne Avatar answered Oct 12 '22 15:10

payne


Late to the party - I think this is the second time I've ended up on this SO post so I'll share my js-based solution (I ended up making a bookmarklet by just fetching and searching the html pages). You can either create a bookmarklet from this, or simply paste the whole thing into the console. Works on chromium-based and firefox:

EDIT: if there are more than 10 or so forks on the page, you may get locked out for scraping too fast (429 too many requests in network). Use async / await instead:

javascript:(async () => {
  /* while on the forks page, collect all the hrefs and pop off the first one (original repo) */
  const forks = [...document.querySelectorAll('div.repo a:last-of-type')].map(x => x.href).slice(1);

  for (const fork of forks) {
    /* fetch the forked repo as html, search for the "This branch is [n commits ahead,] [m commits behind]", print it to console */
    await fetch(fork)
      .then(x => x.text())
      .then(html => console.log(`${fork}: ${html.match(/This branch is.*/).pop().replace('This branch is ', '')}`))
      .catch(console.error);
  }
})();

or you can do batches, but it's pretty easy to get locked out

javascript:(async () => {
  /* while on the forks page, collect all the hrefs and pop off the first one (original repo) */
  const forks = [...document.querySelectorAll('div.repo a:last-of-type')].map(x => x.href).slice(1);

  getfork = (fork) => {
    return fetch(fork)
      .then(x => x.text())
      .then(html => console.log(`${fork}: ${html.match(/This branch is.*/).pop().replace('This branch is ', '')}`))
      .catch(console.error);
  }

  while (forks.length) {
    await Promise.all(forks.splice(0, 2).map(getfork));
  }
})();

Original (this fires all requests at once and will possibly lock you out if it is more requests/s than github allows)

javascript:(() => {
  /* while on the forks page, collect all the hrefs and pop off the first one (original repo) */
  const forks = [...document.querySelectorAll('div.repo a:last-of-type')].map(x => x.href).slice(1);

  for (const fork of forks) {
    /* fetch the forked repo as html, search for the "This branch is [n commits ahead,] [m commits behind]", print it to console */
    fetch(fork)
      .then(x => x.text())
      .then(html => console.log(`${fork}: ${html.match(/This branch is.*/).pop().replace('This branch is ', '')}`))
      .catch(console.error);
  }
})();

Will print something like:

https://github.com/user1/repo: 289 commits behind original:master.
https://github.com/user2/repo: 489 commits behind original:master.
https://github.com/user2/repo: 1 commit ahead, 501 commits behind original:master.
...

to console.

EDIT: replaced comments with block comments for paste-ability

like image 3
p-mcgowan Avatar answered Oct 12 '22 14:10

p-mcgowan