JMRI Code: Developing with JMRI
BackgroundAnybody is welcome to get a copy of the JMRI code and modify it for their own purposes. What makes one a JMRI developer is contributing those modifications back for others to use.
This page discusses how to do that, assuming that you have access to a copy of the code following this procedure.
See the JMRI Git FAQ page for more details on these processes.
The links to the left provide more information on building with specific tools. You should read the page for your particular setup.
The rest of this page provides an overview of the process of developing JMRI code with Git. Basically, you create a new branch, make your changes, compile/run/test until you've finished your intended change, and then send that change back for inclusion into the main repository.
That's done with a four-step process:
- You create a Git branch to hold your work.
- You periodically "commit" your changes to your local repository.
- You periodically "push" those changes to a repository of your own on GitHub.
- When your change is complete, you create a "pull request" that allows JMRI to get your change from your GitHub repository and merge it into JMRI's main repository.
Create a Branch for DevelopmentGit is very good at keeping development on parallel "branches" separate. Although the primary development is on the "master" branch, we strongly recommend that you don't directly make changes to that. There are a lot of JMRI developers, and having them all work on a single branch can get confusing. Instead, you should create a separate branch for each of your projects, work on it until it's ready to be merged back into the main JMRI source, and then contribute the entire branch contents back to our main repository.
To create a new branch:
git checkout master
git checkout -b my-new-feature-or-fix
The first two "git checkout master" & "git pull" lines makes sure that you are starting from the most recent "master" branch contents. The master branch is where we do development between test releases.
The -b option in the last line creates a new branch which will contain your new work. This lets you work on it without interference from other people's changes until you're ready to merge with those. The "checkout" means that you're now working on that new branch, which will hold whatever you commit in later steps.
Develop and Test LocallyNow that you have a copy of the code available, you can directly work in it to develop any changes you want to make. There are several different ways to do that, see the sidebar, including using Ant from the command line, using the NetBeans IDE, using the Eclipse IDE, and using the IntelliJ IDE. You use one of those to compile your code and organize it so that it can be run, and then to run both the individual programs (PanelPro, DecoderPro et al) and various tests that it's all still working.
There's not much to worry about here. If you make a bad change, you can get back the original (last changed in your checked-out branch) version with e.g.
git checkout -- xml/decoderIndex.xml(Note the two dashes, and change the file path to the one you want changed back) Any changes you do make aren't recorded until you commit them, see below.
There are two things you should be careful of:
- You have to tell git about new files that you create:
git add java/src/jmri/util/MyNewFile.javaIf you don't do that, by default git ignores a new file. This can be very confusing with a new file doesn't end up in the git repository. Also, create new files as "readable by anybody"; if you create them in a protected or locked mode, git can have trouble processing them.
- Never, really never, copy files out of or into a
git-managed directory. Just don't do it. It might seem
reasonable to "set a copy of the old files aside", and
then pull them back in later (instead of using
git checkout --to get back older versions) but this can lead to you (accidentally) deleting other people's work. This is Very Not Good. Don't copy files in and out of your repository space. If you're trying to do something special, and you think that copying in and out is the only way to do it, ask for help: There are ways of doing everything you want done without risking the loss of other people's work.
As you work, we encourage you to add a brief description of your changes to the draft release note, which can be found in the help/en/releasenotes directory as the help/en/releasenotes/current-draft-note.shtml file. When your changes are eventually merged into the main repository and included in a release, this will be how other JMRI users find out about them. You can also cut&paste what you write here into your pull request (see below) to help explain your change to the people reviewing it. If your work requires that the users be warned about something, i.e. to do a migration, please also add that to the help/en/releasenotes/current-draft-warnings.shtml file which works similarly.
Commit Changes to Your Local RepositoryYou should commit your changes into your local repository often.
With the older SVN system, there was one central repository that everybody shared. Git provides everybody with their own local repository, and then links them together with "pull", "push" and "pull request" operations. When you commit, you're saving a copy of your changes into your local repository where they're safe, and can eventually be moved onward.
git commitWhen you do this, Git will open an editor window for your commit note. The top line becomes the summary, which should be clear by itself as this will appear in lists of changes. You should keep that summary to 50 characters or less, so it can be displayed compactly. Please add more detail in additional lines after the summary, because that helps your friends and colleagues understand what you've done.
Get Your Own GitHub Repository
- Get a GitHub account and login
- Tell GitHub to "fork" JMRI's repository into one of your own. There's a good help page, but basically you go to the JMRI repository page and click the "fork" button in the upper right.
This gives you your own repository, which you can then work with freely.
If you're using the command line, the next step is to connect it to your local repository. (IDE users will do this next part in their IDE, see those instructions) On the web page for your repository, right side, is a "HTTPS Clone URL". Copy that. In your repository directory on your local computer, do
git remote set-url --push origin https://github.com/yourname/JMRI.git git remote add yourname https://github.com/yourname/JMRI.git(With the appropriate URL, changing "yourname" to your GitHub account name in three places)
After this, doing a "git push" will push your changes up to your repository. "git pull" will still pull from the main repository so that you can get the most recent updates from others. To check this, do a "git remote -v" which should show: (OK if it shows others or the order is different)
% git remote -v
origin https://github.com/JMRI/JMRI.git (fetch)
origin https://github.com/yourname/JMRI.git (push) yourname https://github.com/yourname/JMRI.git
Push Your Changes to Your GitHub RepositoryNow that you have a consistent set of changes committed locally, you can move them up to your repository on GitHub. That makes them visible to everybody else.
Possible Problems and SolutionsSometimes, git will tell you that you need a more complicated push comment, with some options that start with - or --. Just copy and paste that line to execute it. For example, you might get an error message like:
% git push fatal: The current branch my-branch has no upstream branch. To push the current branch and set the remote as upstream, use git push --set-upstream origin my-branchJust go ahead and do what it says:
git push --set-upstream origin my-branchAnd occasionally, your local repository can be out of sync with your GitHub repository. If you get a message about "failed to push some refs" or similar, without specific commands to fix it, do (the first command here is why we created that remote with your name above; make sure it's there, and substitute your GitHub name in the first line):
git pull yourname(If any lines are flagged as conflicts, edit those to remove the conflicts, then "git add" them to resolve the conflict)
git commit -m "merging pull back" git pushIt is definitely easier to do this if you have no modified files in your repository, e.g. you've committed all your local changes.
Submit a Pull RequestOnce your changes are complete and ready to go, the last step is to make your changes, already visible in your GitHub repository, known to the JMRI maintainers so that one of them can pull it into the main JMRI repository. To do that, you create and submit a "pull request" that automatically has all the needed info.
- Login to GitHub and go to the page for your JMRI clone repository (yours, not the main JMRI one)
- There's a "Pull Request" button at the upper right of the file listing. Click it.
- On the next page, select the branch you've been working on and click the "Create pull request" button.
- Fill out the forms. A short title that describes the feature you've written helps other people find it. A few lines in the comment about what it does, how you added it, etc helps users understand the value of your feature. If you've already made an entry in the draft release note (see above), that can be a used here.
- Click "Create pull request". That submits all the info, starts the Continuous Integration (CI) tests and notifies the JMRI maintainers.
- One of the JMRI maintainers will check over your code and the test results, and then either contact you for more info (occasionally), or merge it into the master branch in the the main repository (more often). You are automatically signed up for notifications when things happens.
Sometimes, a maintainer will put a label on your PR
to indicate its status. Some of the more interesting ones are:
- "After Next Test Release" and "After Next Production Release" - placed when a PR should be merged later for some reason
- "Add To Next Release" - needs to be merged before the next release is built
- "dev/test/publish infrastucture" - there's a lot of automation around building and publishing JMRI. This change is to that infrastructure, not the released JMRI code itself.
- "Contribution" - On an Issue, it indicates that the Issue contains a contributed file that some maintainer should merge via a PR.
- "Cleanup" - a change that improves the code, but doesn't really affect JMRI users directly
- "Support Request" - A request for help figuring something out, typically found in the Issues section. Typically these items are closed if resolved, or become "Enhancement" or "Bug" items.
- "Enhancement" - request that somebody make JMRI better in some way.
- "Bug" - a problem that's bitten at least one person.
- "Duplicate", "Invalid", "Won't Fix" - items that have (typically) been closed without action. Issues and PRs never go away, but these labels mark them as not intended for further consideration.
- In addition to the labels, there's a "WIP" tag. It means "Work In Progress", and marks a PR as not yet ready to merge because additional work (usually commits) is needed before merging. Think of it as a blue flag on a train that indicates it's not ready to move. It's added at the front of the PR's title, i.e. "WIP: My Fix", by editing the title with the pencil icon to the right.
- If there are any problems found in the CI test process, you can make additional edits, commit those files to the same branch, and push them to your repository. That'll get them included in an updated version of your PR automatically, rerun the tests, etc.
- Once the code gets merged, it'll automatically show up in the next regular test release.
Once your PR is merged, a
git checkout master; git pull
will bring it back around to your repository and that cycle will be complete.
While all this is happening, you can work on something else by creating another branch and making changes there. But first, pick up the most recent contents of our central repository with:
git checkout master git pullThen you can create a new branch for a new project:
git checkout -b another-new-feature
just like you did at the start of this process, and continue to develop.
After Your Pull Request Is MergedOnce the changes in your PR has been merged onto the master branch, it will be included in the next development release built by our CI system. These packages can be downloaded and run to check that everything is working. You can also refer users to the built installers so they can test your changes.
Approximately once a month, the contents of the master branch are taken and used to build a test release. These are announced to the user community to simultaneously make new features and fixes available, and to put the most recent code into wider use to flush out problems. The build process is documented separately. People are encouraged to download and use these, then report any problems via GitHub or the jmriusers group.
Approximately twice a year, a similar process is used to build production releases.
Who are these people?JMRI is the work of several hundred people. Anybody can contribute their work, large or small to JMRI, either by creating a PR (see above) or in other ways. You don't need any special status to create a PR and have it evaluated, just an ability to follow these instructions.
There's a group of people with "developer" status on the JMRI GitHub project who work more generally on JMRI code, for example taking on and resolving Issues opened by others. These people can assign Issues and PRs to themselves, and do a few other minor things. Typically, once somebody has solved a couple of Issues, they'll get an automated invitation to developer status from GitHub. These people are expected to be subscribed to the jmri-developers mailing list and to have public GitHub profiles that identify them.
A smaller group of JMRI "maintainers" on GitHub have the ability to edit, label and close all Issues and PRs, and to merge the contents of PRs to the main repository. This group does the infrastructure work that keeps the project code moving forward while avoiding unnecessary risk to the project's code and other assets.