In this post I describe my experience of making my first contribution to a project on SourceForge, using the Mercurial version control system. It's sometimes easy to forget there's a world outside of Git and GitHub, and it was interesting dipping a toe in!
At Elevate Direct, we use a library called Sasa quite extensively in our .NET projects. It contains a variety of utility types, but we use it primarily for the implementation of functional concepts like
Option<>. The library has been around for a long time (since 2013), and at the start of 2019, Sandro Magi added .NET Standard support.
He did a great job supporting a wide range of platforms by targeting .NET Standard 1.3. Unfortunately, if you're using a platform that supports
netstandard2.x, then referencing a
netstandard1.x package can result in a huge dependency tree being dumped in your folder output.
To work around this issue for consumers, library authors can add an additional
netstandard2.x target to their library. Unfortunately that can cause issues for people targeting
net461. If you follow the official advise on cross-platform targeting to its conclusion, eventually you end up targeting at least four frameworks:
netstandard1.xfor maximum compatibility
netstandard2.xto avoid large dependency trees in .NET Core 2.x etc
net461to avoid issues caused by
net461's "fake" .NET Standard 2.0 support
net472to "override" the previous
net461target, as .NET Framework 4.7.2 includes real .NET Standard 2.0 support.
If you already have a library targeting
netstandard1.3, then adding the extra targets is pretty easy: just change this line in your .csproj project file:
to this (note the
Given all the hard work had been done to convert Sasa to use .NET Standard 1.3, I thought I'd help out by making the update, and sending a PR. I envisioned a 20 minutes piece of work, tops.
Then I realised the project was hosted on SourceForge, and uses Mercurial for version control.
I've pretty much gone my whole life barely using SourceForge. I'm sure I've downloaded a few things here and there, but I've certainly never hosted, contributed, or even really looked at any projects on there.
Unlike GitHub, where the code is front-and-center when you view a repository, it feels like you have to go hunting a bit further on SourceForge. The project landing page is much more focused on downloads and project activity (and Ads 🤮) but overall the process of submitting a patch should be quite familiar in principal if you're used to GitHub.
Start by clicking the Code tab in the project, which for the Sasa project takes you to https://sourceforge.net/p/sasa/code/. This is similar to the default GitHub view, and is where you can browse the code, view branches and commits, and fork the project.
Just as with Git and GitHub, if you want to send a patch to a project on SourceForge, you first need to fork the code (i.e. create a "personal" copy of the project). After clicking Fork from the code page, you'll be taken to your fork of the project. After a few moments, the clone will be complete and you'll see a copy of the code in your account:
I assume the
u/prefix is to indicate that this is a clone of an existing project, but I'm not sure. It also mentions that the project is a clone of Sasa in the left sidebar.
Once the project is forked, it's time to download the code and make the fix. Sasa uses Mercurial source code management (rather than Git), so you need to install and use the
hg tool. I've used SVN before, but never Mercurial so was interesting to give it a try.
The nerd in me loves that their tool is
hg, the chemical symbol for mercury. But I'm not sure about having a version control system who's name means "subject to sudden or unpredictable changes of mood"!
After a brief read of the Mercurial about page, it actually looks pretty interesting. It sounds very much like Git in a lot of ways, and was started about the same time. It's a distributed version control system, and branching and merging are cheap, just like Git. It does have some interesting extra features, but frankly it seems like Git has already won, so I probably won't be looking into any more than the basics 😉
You can download Mercurial from their website. As it's mostly written in Python, cross-platform installers are available for loads of different operating systems (compare that to Git, where Windows definitely used to feel second-class!) Version 4.9.1 was the latest at the time I downloaded the Inno Setup installer - x64 Windows, though I see version 5.0 is out now.
Once downloaded and installed, you can test everything is working correctly by typing
hg at the command line:
> hg Mercurial Distributed SCM basic commands: add add the specified files on the next commit annotate show changeset information by line for each file clone make a copy of an existing repository commit commit the specified files or all outstanding changes diff diff repository (or selected files) export dump the header and diffs for one or more changesets forget forget the specified files on the next commit init create a new repository in the given directory log show revision history of entire repository or files merge merge another revision into working directory pull pull changes from the specified source push push changes to the specified destination remove remove the specified files on the next commit serve start stand-alone webserver status show changed files in the working directory summary summarize working directory state update update working directory (or switch revisions) (use 'hg help' for the full list of commands or 'hg -v' for details)
Glancing through those commands as a Git user should look vaguely familiar -
status - they're definitely similar in many ways. Just as with Git, you need to setup your username locally. create a new file at %USERPROFILE%/mercurial.ini with the format shown below and add your username and email:
[ui] username = Andrew Lock <[email protected]>
At this point, Mercurial is installed and ready to go, but we don't have any code on our machine yet.
Cloning the repository creates a copy of it on your local machine, including all the branches and history, just like with Git. The code page in SourceForge shows the command you need to run. In my case, it was
hg clone ssh://[email protected].code.sf.net/u/andrewlock/sasa u-andrewlock-sasa
This command clones the repository into a folder called u-andrewlock-sasa. You'll need to confirm the authenticity of the SourceForge host, and enter your password:
> hg clone ssh://[email protected].code.sf.net/u/andrewlock/sasa u-andrewlock-sasa The authenticity of host 'hg.code.sf.net (188.8.131.52)' can't be established. ECDSA key fingerprint is SHA256:FeVkoYYBjuQzb5QVAgm3BkmeN5TTgL2qfmqz9tCPRL4. Are you sure you want to continue connecting (yes/no)? Please type 'yes' or 'no': Password: remote: Warning: Permanently added 'hg.code.sf.net,184.108.40.206' (ECDSA) to the list of known hosts. requesting all changes adding changesets adding manifests adding file changes added 2168 changesets with 7095 changes to 956 files (+8 heads) new changesets 69e92c5f6c58:86c9bcbc342c updating to branch default 223 files updated, 0 files merged, 0 files removed, 0 files unresolved
At this point you'll be checked out on the default branch in the working directory. Rather than mess with branches, I decided to commit straight to the default branch, as I was working in a clone of the real project anyway.
I edited each of the .csproj project files and replaced
Once I confirmed everything was building correctly, I was ready to commit the changes. You can check the current status of the working directory by running
hg status. This shows the files modified, added, and deleted.
> hg status M Sasa.Binary\Sasa.Binary.csproj M Sasa.Collections\Sasa.Collections.csproj M Sasa.Concurrency\Sasa.Concurrency.csproj M Sasa.Linq.Expressions\Sasa.Linq.Expressions.csproj M Sasa.Linq\Sasa.Linq.csproj M Sasa.Mime\Sasa.Mime.csproj M Sasa.Net\Sasa.Net.csproj M Sasa.Numerics\Sasa.Numerics.csproj M Sasa.Parsing\Sasa.Parsing.csproj M Sasa.Reactive\Sasa.Reactive.csproj M Sasa.Web\Sasa.Web.csproj M Sasa\Sasa.csproj
To commit the changes, use the command
hg commit, and provide a message.
hg commit -m "added additional target frameworks"
Note that unlike Git, there's no "staging" area or "index". You just commit the files that have changed. Even though I use the staging area quite a lot, that definitely seems like a plus for users who are new to source control.
At this point, the changes are committed locally, but not yet pushed to the server. You can push using the command
> hg push pushing to ssh://[email protected].code.sf.net/u/andrewlock/sasa Password: searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 12 changes to 12 files remote: <Repository /hg/u/andrewlock/sasa> refresh queued.
Checking on SourceForge, you should be able to see your new commit alongside the changed files:
Now that the code is on SourceForge, you can create a "merge request", to merge the code back into the original project.
Merge Requests are the SourceForge equivalent of GitHub's Pull Requests (PRs). It's a notification sent to the owner of the project that you have changes for them to review and merge.
Choose Request Merge from the left hand sidebar of your clone. This takes you to the Request merge page, where you can enter a title, chose the source and destination branches, and enter a description. This should be very familiar if you're used to GitHub, though the description text isn't markdown unfortunately.
After creating the merge request, the owner of the repository will hopefully receive a notification, and they can review (and hopefully merge) your code! You can track the merge request in the original project's repository (i.e. in Sasa's repository in my case).
It took a while (thanks to a lack of notification from SourceForge it seems), but my contribution was merged! Success 🙂
Trying out both SourceForge and Mercurial for the first time was interesting. Mercurial was super easy to use, and looks like it would generally be easier to get into than Git for newcomers. And I didn't even get to the really interesting parts, like preserving history on file moves or the built in web-server(!). Unfortunately, while Mercurial is in use at some very notable places (e.g. Facebook) and notable projects, it feels like Git has probably won the hearts-and-minds.
And I think part of that has to be thanks to GitHub. It's become somewhat of the de-facto location for open source projects. And after using SourceForge, albeit briefly, I'm not surprised. SourceForge feels like a website from 10 years ago. It's not especially welcoming to newcomers, and was hard to get my head around. I'm just glad the fact the fork/merge request paradigm mirror's GitHub's terminology. If it didn't, I doubt I would have ever figured it out before I got frustrated and gave up.
In this post I described the process I went through of submitting a change to a project hosted on SourceForge, using the Mercurial source control system. I described the process of forking a repository, installing Mercurial, cloning a repository, and pushing your changes. Finally, I described how to create a merge request.