Git and Meld Merge Action in a Private – Public Repository

This post continues describing a project having both private content and an open source public version, each in their own Git Repository. Here is Part One where we describe the application's layout and how we work with ORIGIN and UPSTREAM repositories for MASTER and PUBLIC branches respectively.

As a brief project overview, here is the private version of the app, containing a /resources/private folder and a private.txt file in the root. The public version contains a /resources/public area and a public.txt file in root.

The Merging Process

We'll see how Meld and a few Git functions simplify managing our Open Source project while keeping our private content private. To begin we'll perform our first Git function, a merge check to see if we can anticipate any conflicts. Not necessary, but nice to know.

We see that we'll have a couple of conflicts to resolve. Not a problem! The “mergecheck” alias looks like this.

mergecheck = "!f(){ git merge --no-commit --no-ff master; \
git merge --abort; \
echo \"Merge aborted\"; };f"

As we mentioned, the private branch has private resources in /resources/private. Those resources are in the repository and git merge is going to operate on those files like any other so we need to perform the following steps:

  1. Merge master with public but don't commit anything
  2. Reset the /resources/private contents so we can delete if from the public branch
  3. Delete /resources/private

Here's the function in .bashrc that performs those steps for us.

#git=rmv -- Merges Master branch into Public without Master Private content
git merge master --no-commit &> /dev/null;
git reset src/main/resources/private &> /dev/null;
rm -rf src/main/resources/private &> /dev/null;

Meld Nirvana

If we were to perform a $git status at this point we would be informed that we are still in the merging process, so let's finish it with Meld.

We anticipated a conflict or two in this merge from our mergecheck alias. To confirm that we see our GitworkLauncher class is in red which indicates a conflict.

We also have a Git alias that will list any conflicts for us rather than rely on the GUI.

The “conflicts” alias looks like this.

diff --name-only --diff-filter=UNow we get to enter Meld Nirvana with a .bashrc function called git-meld-merge(). It looks like this

git mergetool --tool=meld > /dev/null 2>&1

and the Nirvana part:

Using Meld for DIFFs

We want to make sure we're using Meld for all Diffs as well. We want to use Meld Directory Mode whenever possible, if not, say we have 10 or 100 files that are different between two branches we DIFF. Without launching in Meld Directory Mode we're firing Meld for each and every file. Not optimal.

So we added a bash script in our path called that looks like this.

meld "$2" "$5" > /dev/null 2>&1

Then we assign that external command in our .gitconfig [diff] section.

tool = meld
external = /home/daveburke/scripts/

When we need DIFF-DIRECTORY mode we've got that covered, too. A .bashrc function called git-diffdir() will compare practically any two Git objects (branches, commits, HEAD, staged changes) in Meld Directory mode.

git difftool --dir-diff --tool=meld --no-prompt $1 $2 > /dev/null 2>&1

Here is the DIFF between MASTER and PUBLIC branches for example.

Why .bashrc functions

You're probably wandering why we're using .bashrc and not git aliases for some of these functions. It's primarily to avoid annoying Gtk-Warnings and other messages on launch like those you see here.

Merging in Review

To review, we've got an application with private content we don't want in the Open Source public repo. With our Git customizations our everyday work processes are as follows.

  1. Code, stage and commit our MASTER branch work
  2. Checkout our PUBLIC branch and if we want we can get a preview of the upcoming merge with $git mergecheck
  3. Merge MASTER and remove any private content along the way with $git-rmv
  4. View conflicts with $git conflicts and fire up Meld with $git-meld-merge
  5. Code and test in PUBLIC, using $git diff or $git-diffdir for any comparisons along the way.
  6. Push PUBLIC to the UPSTREAM repo's MASTER branch for which we use an alias called $git push-public
  7. Return to MASTER, lather, rinse and repeat!