Saturday, February 28, 2015

Sharing Contributions with ForgeRock via Git Subtree part 2

In my previous post we used Git's subtree feature to pull an existing subdirectory out of a larger maven project and push it to a third party repository for contributing just that subdirectory and below to open source. In today's post we'll see how to tie that subtree to that external repository, make some changes, and selectively push those changes up as well among a few other things.

Replacing with the Now External Source

Currently we have made our subdirectory into a subtree and used a branch to push just its contents and nested directories and resources out. But those contents are still there and not yet tied to the external location that will be the source going forward. Our first step is to remove the existing items.

Back in the root of our main project directory we remove the original directory and correspondingly its subtree to get rid of the original items. Then we commit those changes without pushing. That leaves us one commit ahead of origin/master, the remote on-premise repo. That is an important point to remember.

git rm -r openam-authentication/openam-auth-radius
git commit -m "remove openam-auth-radius to replace with subtree"

Then we define a new remote for referring to the external repository and create a new subtree with that remote as its source. The --squash parameter  means that we only get one commit added to our history indicating the update to the subtree from the repo.

git remote add 
  ext-radius https://github.com/...<fill-in-your-repo>

git subtree add --prefix=openam-authentication/openam-auth-radius 
  --squash ext-radius master

When I did this I ran into the following error on that second command:

prefix 'openam-authentication/openam-auth-radius' already exists.

The directory was still there. Only the Git tracked resources were removed. There was still a target directory left over from the last time I did a build and its contents were still sitting in there. So I used rm -rf to remove the directory completely. Running that second command again resulted in this output from Git:

git fetch ext-radius master
From https://github.com/...<fill-in-your-repo>
 * branch            master     -> FETCH_HEAD
 * [new branch]      master     -> ext-radius/master
Added dir 'openam-authentication/openam-auth-radius'

Interestingly, if we run git status at this point we are now three commits ahead of origin master. Running git log shows those three commits at the top. The second commit holds the link to the current commit of the external upstream repo. That highlighted commit matches the most recent commit in the repo.

commit ee4b098ad60e55f419789a82a0dc80bd949a3609
Merge: 0ae47a3 ceef534
Author: Mark R. Boyd <boydmr@ldschurch.org>
Date:   Thu Feb 26 10:36:10 2015 -0700

    Merge commit 'ceef534cae7ff8cba41a204867b03766d4422c4b' as 'openam-authentication/openam-auth-radius'

commit ceef534cae7ff8cba41a204867b03766d4422c4b
Author: Mark R. Boyd <boydmr@ldschurch.org>
Date:   Thu Feb 26 10:36:10 2015 -0700

    Squashed 'openam-authentication/openam-auth-radius/' content from commit 2c46086

    git-subtree-dir: openam-authentication/openam-auth-radius
    git-subtree-split: 2c4608649741ce14ce09e21bd766681bf6d219f3

commit 0ae47a3f1f64238ab95883cf9ba22dd01c85911b
Author: Mark R. Boyd <boydmr@ldschurch.org>
Date:   Thu Feb 26 10:28:30 2015 -0700

    removed openam-auth-radius to replace with subtree


If I now look in the openam-auth-radius directory I see my files have been restored. But at this point the files from that directory on down are associated with the upstream external repo. Now lets push to our internal repo shared by the team. In the root of the project I run:

git push

Impact on Other Team Members?

So how do other members of my team see these changes? To simulate another team member I'll clone our on-prem openam repo into another directory, openam2, and then run a maven build:

cd ..
mkdir openam2
git clone https://BoydMR@...<internal repo path> openam2
cd openam2
mvn clean install

Everything builds just as it always has. And why wouldn't it? If you look in the openam-authentication/openam-auth-radius directory the source code is there in contrast with Git submodules whose source isn't in the repo but must be pulled by each user separately. With subtrees the source is in our repo so everyone works just as they always have and knows no difference unless they need to fetch from or push to the subtree's upstream external repo. As long as they are working with the internal remote repo used by the team they see no difference.

Sharing Changes via Internal Repo

To that point, lets try making changes at this point. To be clear, changes may be pushed into the team's internal repo or pushed from the subtree into its external remote by either me or my coworkers. We'll try both. First I'll do the former.

Lets say one of my coworkers needs to tweak a file. Mimicking a coworker I use the openam2 copy of the project and make an edit, commit, and push to the on-premise repo.  I've trimmed some of the path for readability.

git add openam-authentication/openam-auth-radius/src/main/java/.../ConsoleClient.java

git commit -m "removed double print of build date from ConsoleClient startup"

git push

As a member of the team I'd see these changes when next I fetched commits and did a diff with the internal on-premise repo or just did a pull there from. Back in the openam directory and hence a different repo I see the following after doing the fetch to get commits from the internal repo. Recall that this gets commits that I don't have locally but does not merge them into the current branch in contrast to a pull which does both:

git fetch 

git diff master origin/master

And in the output I'll see any changes that were made. And a git status at this point tells me that my current branch master is behind origin/master by one commit since we did a fetch and not a pull. But note that I did not specify a remote. By default it uses the origin remote. If we did a fetch from the remote associated with our subtree we won't get anything brought in from their either because nothing has changed. So lets try that route next.


Seeing Changes in Subtree's External Upstream

Suppose that my coworker made changes to what is now tracked in our subtree directory of openam-authentication/openam-auth-radius and pushed them into the subtree's external upstream remote repo. To simulate that I move to the openam2 directory, edit a file, and commit but will leave those details out to save space. To push to the upstream we need first to add the remote. We have that already in the repository of the openam directory but didn't add it to this repo yet. Once added we then subtree push to the upstream:

git remote add upstream-radius https://github.com/...<fill-in-your-repo>

git subtree push   --prefix=openam-authentication/openam-auth-radius   upstream-radius master


Again we get some interesting output from that last command:

git push using:  upstream-radius master
-n 1/     109 (0)
-n 2/     109 (1)
-n 3/     109 (2)
...
-n 108/     109 (106)
-n 109/     109 (107)
Counting objects: 27, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (15/15), 6.14 KiB | 0 bytes/s, done.
Total 15 (delta 3), reused 0 (delta 0)
To https://github.com/...<fill-in-your-repo>
   2c46086..dd773db  dd773dbe09d065a440f67021f0d309ff4acb7939 -> master

Now that my coworker placed changes in the external library I have older code in my openam repo subtree. But how can I tell that? The steps are the same as with a regular remote. I first do a fetch from that remote to gather those changes. Remember that in the openam repo the remote is ext-radius

git fetch ext-radius master 

The output from this command is:

remote: Counting objects: 15, done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 15 (delta 3), reused 15 (delta 3), pack-reused 0
Unpacking objects: 100% (15/15), done.
From https://github.com/ForgeRock/radius-server
 * branch            master     -> FETCH_HEAD
   2c46086..dd773db  master     -> ext-radius/master

And again, now that we have fetched those changes into our repo we can see what effect they will have without pulling them into our current branch:

git diff master origin/master

And sure enough I'll see the changes and how they'll impact my local source. In my next post I'd like to take this one step further and consider how I would collaborate on that upstream library, itself a single maven submodule, a subdirectory, if I didn't have write privileges on it as I have had here. 

See you then.   


No comments:

Post a Comment