Child pages
  • HowTo -- MPS and Git

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 4.0
Wiki Markup
h1. Working with MPS and git

This section explains how to use git with MPS. It assumes a basic knowledge
of git and the git command line. The section focuses on the integration with
MPS. We will use the git command line for all of those operations that are not
MPS-specific.

We assume the following setup: you work on your local machine with a clone of an
existing git repository. It is connected to one upstream repository by the name
of {{origin}}.

h2. Preliminaries

h3. VCS Granularity

MPS reuses the version control integration from the IDEA platform. Consequently,
the granularity of version control is the file. This is quite natural for
project files and the like, but for MPS models it can be confusing at the
beginning. Keep in mind that each *model*, living in solutions or
languages, is represented as an XML file, so it is these files that are handled
by the version control system.

h3. The MPS Merge Driver

MPS comes with a special merge driver for git (as well as for SVN) that makes
sure MPS models are merged correctly. This merge driver has to be configured in
the local git settings. In the MPS version control menu there is an entry
*Install Version Control AddOn*. Make sure you execute this menu entry
before proceeding any further. As a result, your {{.gitconfig}} should contain
an entry such as this one:

{code}
[merge "mps"]
	name = MPS merge driver
	driver = "\"/Users/markus/.MPS20/config/mps-merger.sh\" %O %A %B %L"
{code}


h3. The .gitignore

For all projects, the {{.iws} file should be added to {{.gitignore}}, since
this contains the local configuration of your project and should not be shared
with others.

Regarding the (temporary Java source) files generated by MPS, two approaches are
possible: they can be checked in or not. Not checking them in means that some of
the version control operations get simpler because there is less "stuff" to deal
with. Checking them in has the advantage that no complete rebuild of these files
is necessary after updating your code from the VCS, so this results in a
faster workflow. 

If you decide *not* to check in temporary Java source files, the following
directories and files should be added to the {{.gitignore}} in your local
repo:

* For languages: {{source\_gen}}, {{source\_gen.caches}} and 
  {{classes\_gen}}
* For solutions, if those are Java/BaseLanguage solutions, then the same
  applies as for languages. If these are other solutions to which the
  MPS-integrated Java build does not apply, then {{source\_gen}} and
  {{source\_gen.caches}} should be added, plus whatever else your own build
  process creates in terms of temporary files.

Make sure the {{.history}} files are *not* added to the {{gitignore}}*!
These are important for MPS-internal refactorings.

h3. MPS' caches and Branching

MPS keeps all kinds of project-related data in various caches. These caches are
outside the project directory and are hence not checked into the VCS. This is
good. But it has one problem: If you change the branch, your source files
change, while the caches are still in the *old* state. This leads to all
kinds of problems. So, as a rule, whenever you change a branch (that is not
just trivially different from the one you have used so far), make sure you
select {{File -> Invalidate Caches}}, restart and rebuild your project.

Depending on the degree of change, this may also be advisable after pulling from
the remote repository.


h2. Committing Your Work

In git you can always commit locally. Typically, commits will happen quite
often, on a fine grained level. I like to do these from within MPS. The screenshot below
shows a program where I have just added a new variable. This is highlighted with
the green bar in the gutter. Right-Clicking on the green bar allows you to rever
this change to the latest checked in state.


!green.jpg|border=1!


In addition you can use the {{Changes}} view (from the 
{{Window -> Tool Windows}} menu) to look at the set of changed files. In my case
(\fig{changesview}) it is basically one {{.mps}} file (plus two files realted
to writing this document :-)). This {{.mps}} file contains the test case to
which I have added the new variable.


!changesview.jpg|border=1!


To commit your work, you can now select {{Version Control -> Commit Changes}}.
The resulting dialog, again, shows you all the changes you have made and you can
choose which one to include in your commit. After committing, your {{git status}} 
will look something like this and you are ready to push:

{code}
Markus-Voelters-MacBook-Air:lwes-assembla markus$ git status
# On branch demo
# Your branch is ahead of 'assembla/demo' by 1 commit.
#
nothing to commit (working directory clean)
Markus-Voelters-MacBook-Air:lwes-assembla markus$ 
{code}

h2. Pulling and Merging

Pulling (or merging) from a remote repository or another branch is when you
potentially get merge conflicts. I usually perform all these operations from the
command line. If you run into merge conflicts, they should be resolved from
within MPS. After the pull or merge, the {{Changes}} view will highlight
conflicting files in red. You can right-click onto it and select the 
{{Git -> Merge Tool}} option. This will bring up a merge tool on the level of the
projectional editor to resolve the conflict. Please take a look at the
screencast at 

{code}
     http://www.youtube.com/watch?v=gc9oCAnUx7I
{code}

to see this process in action.

The process described above and in the video work well for MPS model files.
However, you may also get conflicts in project, language or solution files.
These are XML files, but cannot be edited with the projectional editor. Also,
if one of these files has conflicts and contains the {{< < < <}} and
{{> > > >}} merge markers, then MPS cannot open these files anymore because
the XML parser stumbles over these merge markers.

I have found the following two approaches to work:

* You can either perform merges or pulls while the project is closed
  in MPS. Conflicts in project, language and solution files should then be 
  resolved with an external merge tool such as *WinMerge* before attempting
  to open the project again in MPS.
* Alternatively you can merge or pull while the project is open (so the
  XML files are already parsed). You can then identify those conflicing files
  via the {{Changes}} view and merge them on XML-level with the MPS merge
  tool. After merging a project file, MPS prompts you that the file has been
  changed on disk and suggests to reload it. You should do this.

Please also keep in mind my remark about invalidating caches above.

h2. A personal Process with git

Many people have described their way of working with git regarding branching,
rebasing and merging. In principle each of these will work with MPS, when taking
account what has been discussed above. Here is the process I use.

To develop a feature, I create a feature branch with 

{code}
git branch newFeature
git checkout newFeature
{code}

I then immediately push this new branch to the remote repository as a backup,
and to allow other people to contribute to the branch. I use

{code}
git push -u origin newFeature
{code}

Using the {{-u}} parameter sets up the branch for remote tracking.

I then work locally on the branch, committing changes in a fine-grained way.
I regularly push the branch to the remote repo. In less regular intervals I pull
in the changes from the master branch to make sure I don't diverge too far from
what happens on the master. I use merge for this:

{code}
git checkout master
git pull                   // this makes sure the master is current
git checkout myFeature
git merge master    
{code}

Alternatively you can also use

{code}
git fetch
git checkout myFeature
git merge origin/master    
{code}


This is the time when conflicts occur and have to be handled. In repeat this
process until my feature is finished. I then merge my changes back on the
master:

{code}
git checkout master
git pull                   // this makes sure the master is current
git merge --squash myFeature    
{code}

Notice the {{--squash}} option. This allows me to "package" all of the commits
that I have created on my local branch into a single commit with a meaningful
comment such as "initial version of myFeature finished".