This is a list of Frequently Asked Questions for Git, particularly regarding how we use it
with JMRI.
Click on a question to open the answer.
There's a separate JMRI Help page on how to get the code with Git.
See also the Technical index for more information on maintaining JMRI code.
See also the JMRI general FAQ.
sudo yum install git
or sudo apt-get install git
.That horizontal arrow is the "Pull Request" (and subsequent pull) that records information about how things get into the repository.
The arrows are both operations (push, pull) and also definitions of where to look e.g. a URL. Git can store shorthand for a URL, called a "remote". The default remote is called "origin". You can have many remotes defined.
Via the git command line tool you do this with this command:
$ git remote set-url --push origin https://github.com/username/JMRI.git
username
is your github user name. You can check the current status with
of the push and pull repositories with:
$ git remote -v origin https://github.com/JMRI/JMRI.git (fetch) origin https://github.com/username/JMRI.git (push)
This says that, by default, fetches and pulls come from the main JMRI/JMRI repository. When
you push, on the other hand, it goes to your own repository.
Once you have a copy of your changes on GitHub, it is easy to generate a Pull Request (link to GitHub)
With SVN and CVS, you check out a "working directory" to make your changes in, work in it for a while, and eventually commit all your changes back to the main repository.
Git works on a different idea. Instead of multiple working directories, you have a single repository that's been "cloned" from the main repository. If you're making individual little changes, you can work directly on the default "master" branch within it. If not, see Using Branches, below.
To understand Git, it is good to know about the various places in your local git repository:
.git/
hidden
directory,When you clone a git repo, you are creating a directory structure that holds all of these items. Unless you tell it otherwise, the working tree starts off filled with contents of the master branch of the repo you cloned - and the staging area is empty. As you make changes to the files in the working tree, you need to explicitly add them to the staging area. Git knows about these files, but they aren't yet officially part of your local repo.
Once you have populated the staging area with of all the things you have changed, a
commit operation will, uhm, officially commit your changes to your repo's
.git/
structure.
When you pull or push, you are telling Git to synchronize your
.git/
content with that of the remote repo you originally cloned things
from.
The first step is to log in to GitHub and clone your own copy of the main JMRI repo. This will give you a safe place to push and pull from without impacting others.
$ git clone https://github.com/JMRI/JMRI.git
or
$ git fetch
then
$ git diff ...origin $ git merge origin/master Auto-merging ... files ... CONFLICT (content): Merge conflict in some_file Automatic merge failed; fix conflicts and then commit the result. $ vi some_file # the file has the conflicts marked, edit to fix... $ git add some_file $ git commit -m "Merged master fixed conflict" $ git merge origin/master
or
$ git pull https://github.com/JMRI/JMRI.git
$ git add newfile $ git rm oldfile $ git add . $ git status $ git fetch $ git merge
$ git commit -m "commit message" filename, filename
or
$ git commit -a -m "commit message"
GitHub Desktop is a free application that can do many of the same things that the git command-line tool does, but provides an interface that many people find easier and more friendly.
For more on GitHub Desktop, please see our page on using GitHub Desktop.
After your Commit, a white dot will appear near the end of the line that looks
like a siding in a track plan. Click it to read the title. To see the files
changed at another point in time, click an older commit dot:
After a commit, your new edits are only added to your local copy of your branch.
To have them show up in a place other people can see them, either click the
Sync button at top right, choose Sync (Cmd-S) from the Repository
menu or make Github Desktop automatically sync after every commit by checking the
Automatically Sync after Committing menu item in the Edit menu:
This tells you that new code has been copied to your repo, and in a few seconds this new code is also copied to your computer, so you can view it or use it, unless they've been working on the same lines of code (See Resolve a Merge Conflict, below)
The name of the PR button will change into #123 signaling you can't make another PR in this branch from here (but you can still commit extra edits to it): |
Normally, a PR is meant for the master branch of the _original_ repo, say
JMRI:master. You may pull your PR in your own remote repo, but only a couple of
people, the maintainers, can pull your edits into the "real" JMRI:master. Before they
do that, they study what you've written, maybe even pull it into their own repo to
test it before merging it for every other JMRI user to see.
When your PR is pulled & merged & closed, the PR #123 name will disappear and you may
delete the branch safely.
At the left, the blue rectangle shows how a change can be made.
That basic process is used to make all the changes to the master branch, although for simplicity we haven't shown all the details for all of them.
Sometimes, your development work can take a while. Maybe you do it in several phases, making multiple commits. Before you're finally ready to merge it back into the common code with via a Pull Request (PR), somebody else can make a change on the master branch. The green path shows that case. The branch was created, development took some time, and then a change was made to master (black dot on black line) before the green change was merged back. The merge process in the green arrowhead took care of this. Generally, this is straightforward, because most of the code doesn't change very often: If just a couple changes have been made, they rarely overlap. This motivates our "merge often" philosophy.
Sometimes development goes on for such a long time that people made changes to master that matter to you. Perhaps they're new features or bug fixes that you'd like to have in your own development branch. Or perhaps they're changes that conflict, and you'd like to resolve those conflicts in your own work now, rather than waiting for later.
The 2nd diagram to the right has an example of this. After the programmer created the blue branch for his own work, changes were made on both his branch (first three dots on blue line) and on master (three dots on black line). Sometime after that 3rd change on master, the developer decided to "git merge master" onto his branch, bringing all those changes in via the black diagonal arrow. Both his changes and the changes to master are now present in the blue branch he's working on.
Later, he decides to merge his work back onto master via the blue arrow in the middle.
But at that point, he can still continue to work on his branch (next blue dot). Perhaps he's fixing a bug that was found by a user once the work was merged to master. Or perhaps he's just working more in the same direction. Either way, when he's ready, he can merge again (right-most blue diagonal), or keep working on his branch (blue line running off to right), or merge other people's work to his branch once it's merged (not shown).
By doing your work on your own branch:
The basic idea is important: By working on a branch in your repository, your work can be kept a part of the overall JMRI effort instead of being isolated and unavailable.
We recommend that you name branches starting with your GitHub account name or initials
(for example, "abc") and something that suggests what you are working on:
"abc-decoder-xml-change"
, "abc-2015-09-14"
,
"abc-next-cool-thing"
, and "abc-patch-NNNN"
are all fine. That
way, we know it's you, and you can sort out the rest. Keep the name short & simple enough
to easily type (because people will sometimes have to), and limit it to letters, numbers
and use the "-" instead of spaces; that'll make it easier to work with.
git checkout -b branchnameThe "-b" says to create the branch. To switch to an existing branch, just leave out that option:
git checkout branchnameTo see all the current branches, do
git branch
git checkout branchname git merge -m"merging in current contents of master" master(If you leave off the message option, you may be prompted to add one in an editor) If any changes were picked up and merged in, you can then commit them to your branch:
git commit -a
When you're done, merge your changes back into the common line of development
with
git checkout master git merge -m"merging to master" branchname git commit -a
git checkout master git branch -d branchname
Say Arnie has developed something on the "arnie-great-tool" branch. Bill wants to try to use it on his layout. The steps are:
git checkout arnie-great-tool (work on changes) git commit -m"Added support for the Frobnab 2000" git push
git remote add arnie https://github.com/arnie/JMRI.git git fetch arnie arnie-great-tool git checkout arnie-great-toolwhere the 2nd part of the "remote add" is the URL for Arnie's repository, and you just have to do that command once to define "arnie" as an alias you can use in "git fetch".
git commit -m"Fixed a bug in sternerstat handling" git pushwhich commits the changes and pushes them up into Bill's repository on Github.
Then Arnie can merge those changes into his own copy with:
git checkout arnie-great-tool git pull https://github.com/bill/JMRI.git arnie-great-tool
Click on that name and choose Show in Finder or Open with External Editor (GhDt itself
has no edit tools).
To find the spot where the Conflict occurred, look for the <<< HEAD ====
>>> master
markers that were inserted by GitHub:
Choose which of both versions you wish to keep (or make some combination) and remove the
< === >
lines!
This new proposal should still be Committed to JMRI, so give it a fitting title i.e. "Solve conflict" and click Commit (and Sync). This extra commit will be added to your PR and be part of your proposal the maintainers will see. You shouldn't keep merge conflict lurking overnight, as the maintainers have no way to fix them for you and they will have to ignore it till you solved it.
You can add this to your repositor(ies) so that each push will get automatically tested.
The two CI test services are "Travis CI" and "GitHub":
It's very important that Windows users not accidentally convert a file to CRLF line ends. When that happens, Git thinks that every line has been changed: Git can no longer provide useful, granular history information about earlier changes to the file.
There is a ".gitattributes" file that tells (most) command-line Git implementations how to handle this properly. Unfortunately, not all IDEs obey the directives in the file. For example, to get NetBeans on Windows to handle line-ends properly, a specific plugin must be installed. See the NetBeans JMRI help page for specifics.
If a file with changed line-ends is accidentally committed and forwarded in a
pull-request (PR), the bad file in that PR will be detected during the Travis CI test and
the PI will not be accepted and merged. Further, the PR will be marked
with a "CRLF" label. Since the history has already been lost in this file, the CRLF label
reminds the maintainers that it's not sufficient to just change the line-ends back to LF,
commit and push: The history has been lost, and more complicated measures must be
taken.
The two approaches are:
Maintainers who encounter an updated PR with the CRLF label should check to see that all the files in the PR do not show all lines changed. If they do, even if they have the correct LF line ends, the PR should not be merged.
Many XML Editors have a Preference Setting for line
ends.
For example, in Espresso check that Line Endings are set to Unix (LF)
before starting to edit any JMRI file:
Pull requests are just a special case of a branch. If you want to test them before merging them into master, you can bring them into your local repository and work with them.
In some cases, GitHub Web makes specific instructions available right on the pull-request itself. Look near the bottom of the discussion thread, in the last information block. The nice thing about those is that they automatically have the right branch names, etc, included.
Please note that, in some cases, these have a "Step 1" for looking at the pull request locally, and a "Step 2" for merging it back. Please do not do that Step 2 request from the command line, but instead use the web interface for doing the actual merge.
If no instructions are displayed, here's the sequence of things to do:
user wants to merge 3 commits into JMRI:master from user:branch
git fetch https://github.com/user/JMRI.git branch:local-branch
git checkout local-branchthen compile, test, etc. as you'd like. You can even commit and share changes if you'd like, because this is now your own development branch: It started at the other person's, but it's now your own.
Let's say that you know v4.9.1
does not have the problem, and commit
23482341
(made up number) does. A narrow range is good, but don't spend any
time on it; git bisect does a binary search that's very efficient. Then you check out the
bad version:
git checkout 23482341You start the bisect process:
git bisect start git bisect bad git bisect good v4.9.1
I.e. set up your branch with the problem, start 'git bisect', tell it the problem is visible here and now, then tell it where there's a good version to search through. Git will sort out the possible revision path(s) where the problem can lie and devise an optimal search. Then it will checkout some place in the middle and tell you "Bisecting: 6 revisions left to test after this" or something like this.
Test that code:
ant clean tests(and whatever you need to recreate). Once you know if it's good or bad, you say
git bisect good
or
git bisect badand repeat. Git will do a good job of giving you the minimal number of tests to do, and in the end will show you the commit that turned "good" into "bad" - not the PR, the single commit. You can then look at the exact changes in that commit to see what went wrong.
After "git bisect" is finished, end the process with
git bisect resetto get back to where you started.
git checkout -b patch-NNNN
where NNNN is the patch number.
git commit -m"Patch-NNNN plus the patch subject line (author name)"
git push origin patch-NNNN
git pull
to update your local repository with this patch on the master branch. Or, if you need
them sooner, you can immediately merge these changes onto your local master via
git checkout master
git merge patch-NNNN
As we migrated from SVN to Git in late 2015, you may still have edits based on old code. If you have changes to the JMRI code in an existing SVN checkout that you wish to commit to the current development version in Git, here's what we recommend:
$ svn update
$ svn status
save a copy to reference later ...
$ svn status > saved-status.txt
$ svn diff > patch.txt
$ git clone https://github.com/JMRI/JMRI.git
$ git checkout tags/svn-30001
This sets your working copy to be exactly the same as the last contents of SVN, the
same as the base for the svn diff
you took earlier.
$ patch -p0 < patch.txt
git add (pathname)
on
each of them to tell Git about them
$ git add pathname/to/new/file
$ git status
You should see the same list of changed files as the "svn status" you ran
earlier.git stash save
git checkout master
git stash pop
Now you can start developing, without having lost anything.
When JMRI was originally using CVS, we used lines like:
# The next line is maintained by CVS, please don't change it
# $Revision$
as an additional way of tracking file versions. When we migrated to SVN, we kept those
lines in certain files, like decoder XML, properties files, etc, that users are likely to
edit and submit back for inclusion.
But with Git, there's less need for these. So we'll be removing these lines as time allows. If you're working on a file and happen to see one, usually in the header, you can just delete it (if it has somebody's name, you might want to add that to the copyright notice if there is one.)