Suppose you have a local GIT repository where dev-stable-topic is the development branch and time to time the releases are made to the customer from a remote GIT repository which has a branch called release-stable from where the selective changes are merge in a controlled way. The remote repository is hosted in a separate linux server.
The local dev branch is where all the development is going on. These are changes not necessarily fully tested yet. But the remote branch is where only well tested and verified changes are merged.
Now the strategy is to try comparing the local branch with the remote branch and see what are the new changes which have been introduced and which are the changes to be merged. Depending on how the project is managed there may be various levels of restrictions, checks and balances to be taken care of while doing this activity. But the underlying technique is the main focus here.
So one the strategy is decided we will now jump into the nitty-gritty of it.
Getting hold of the source repository
$ mkdir ~/repos/dev-stable-topic
$ cd ~/repos/dev-stable-topic
$ repo init -u ssh://xyz-gerrit/Connectivity/Manifest -b dev-stable-topic
$ repo sync
Getting hold of the destination repository
$ mkdir ~/repos/release-stable
$ cd ~/repos/release-stable
$ repo init -u git://abc-git/platform/remote-manifest -b release-stable
$ repo sync
Now, assume this is an android project, the manifests are divided into platform and kernel. The platform project has multiple smaller projects as platform-main and many other. The process is repetitive and hence, discussing one example will be sufficient to understand the others.
Now the strategy is to go into each separate project folder (both for the local branch and the remote branch), take a git log in each and see what has come new in the local (dev branch).
Now, in the our platform-main porject (which is a part of the platform manifest) lets see how our strategy works.
Steps we will follow,
- find out which is the project main folder
- go inside it
- take the git log (in both local and remote branch)
- do a diff and then decide which are the changes to go into the remote.
$ cd ~/repos/dev-stable-topic/device/company-specific-folder/platform-main
$ git log –oneline –decorate –no-color remotes/m/dev-stable-topic > ~/rebase_26_11_2011/platform-main-dev-stable-topic.txt
$ cd ~/repos/release-stable/
$ cd device/company-specific-folder/platform-main
$ git log –oneline –decorate –no-color remotes/m/release-stable > ~/rebase_26_01_2016/platform-main-release-stable.txt
Now we have two files platform-main-dev-stable-topic.txt and platform-main-release-stable.txt which contains the respective git logs. To see what the new changes are in the dev branch we will take a diff of these tew files. I personally use meld tool for diff purposes, you can choose any other tool.
Now from the diff activity you will know what is the last change which was merged into the remote release branch. In a standard diff tool this can observed in nice graphical fashion. Not the hash of the last hash match, say it is 34f84e5. This hash value is important as we want to start our rebase operation (of the branch release-stable stable branch from the dev-stable-topic branch) from this hash point.
Please remember the last match is the starting point of the new rebase operation. Git anyway skips this point and starts rebase/merge from the next hash. So if you already use the next hash value as the starting point, you will actually miss a change set.
Rebasing Using the Rebase command
$ git rebase -i –onto remotes/m/release-stable 34f84e5 remotes/xyz/dev-stable-topic
remotes/m/release-stable is the destination branch and
remotes/xyz/dev-stable-topic is the source/local branch.
Couple of bullet points here:
- After you issue the above command, it will bring up a git screen which is basically a list of patches to be picked by git for the rebase.
- Have a look into the list and see if you want to include all the patches or if you want to exclude some of the patches shown in the list.
- To exclude any patch just remove that form this list.
- Once you are sure the list of patches is what you want to bring in into the destination branch, save the file and exit.
As a preference to editors to do any modification in the above list of changes I prefer VIM over any other editor. So in my configuration I use the below command to change the GIT default editor to VIM:
$~ git config –global core.editor “vim”
After this point, the rebase command tries to merge the patches from the remote.
The branch strings are important here, because unless you use the right branch name string the rebase command would complain and fail.
Finding the name of the remote branch and the destination branch can be achieved in many different ways. One of way to find it is to use the git branch command as below:
$ git branch -a
This command lists all the names of the branches in the present git repository.
If there is no conflict then you should see something like the below on the console:
Successfully rebased and updated detached HEAD.
In case of a conflict you have to resolve the conflict manually. Maybe we will see some merge conflict when we do the kernel rebase.
For resolving Merge Conflict please refer to this post Merge Conflict Resolution in GIT.
Once the merge conflict has been resolved do git rebase continue as below:
“git rebase –continue”
You will have to do the merge conflict as many times as you encounter them and continue with your rebase operation.
If there are multiple project in the same manifest then, you have to carry out separate rebase operation for each and every projects. In each project we can checking what are the differences between the local and the remote branch and then see if we need to merge anything from the local to the remote.
Needless to say if we need to merge anything from the remote to the local the operation will be exactly similar except that the direction of the merge will be opposite.