Tuesday 21 October 2014

Import commits from a branch from external repository

This happened to me when I did the migration from SVN to Git for third time in my career.

Once all the source from trunk and other branches was imported into Git repository, a few set of developers made hotfix changes in svn and pushed it up to the trunk.

I was then asked to import these selective commits into the git's master branch . Unfortunately, I couldn't import these changes straight away into my production git repository as the developers had already started working on it. I as a Git admin, had forked new branches  and commits were pushed up the central repository.

I had to take a different approach and here it is:

1) At the time of Migration, I had a non bare repository where in I used to periodically pull commits from SVN. The repo was /home/mayur/Migration

2) My production git repository,/mnt/Platform.git was a bare repository that was born out of the non bare repository I spoke in point #1.

3)   Now to import the latest changes in my git repository, I decided to

   - First clone from my central repository
     git clone mayur@gitServer:/mnt/Platform.git

   - Now import the latest from svn into my non bare repository,  /home/mayur/Migration and locked         svn's trunk branch via hooks to block any more commits.

   - Now, in the locally cloned repo, I added the origin of my non bare
     repository,/home/mayur/Migration

git remote add svn_origin /home/mayur/Migration
git fetch svn_origin
git checkout -b svn_master svn_origin/master

4) Now I had to diff for commits between svn_master(which is the latest copy of trunk in svn that has hotfix changes) with the git's master branch and cherry-pick them selectively.

So I did,
git log master..svn_master shows everything that master needs to have everything svn_master has.

I dumped all of these commits information into a file .

5) Then I had to cherry-pick the commits into the git's master branch but found a weird issue.
The authors were not correctly set in most of the commits and hence cherry pick failed complaining about it. All the committer names were missing and instead only email ids were observed.

So I had to amend the author name correctly  via ,

git filter-branch -f --commit-filter 'if [ "$GIT_AUTHOR_NAME" = "<user1@abc.com>" ];then export GIT_AUTHOR_NAME="username surname"; export GIT_AUTHOR_EMAIL=username@abc.com;fi; git commit-tree "$@"'

6) Following this I checkout to master branch and cherry-picked  the commits into it with
          git cherry-pick <commit_sha>

Tuesday 19 August 2014

Setting up Git repositories


Setting up user based push on Git repositories

1) Create a group for users who would be pushing code to git repository
# groupadd Git_Users

2) Now add this user on the git server and setup his/her password
# useradd mayur
# passwd mayur

3) Any user(for eg., "mayur" here ) who wishes to push the code on to the git repository must be added
to this group.
# usermod -G Git_Users mayur

4) Now assign the appropriate ownerships (Group and owner) to the repositories.
# chown –R  root:Git_Users  <repository>

5) Assign the required read/write permissions to the repository.
# chmod –R 775 <repository> 

6) Edit the /etc/passwd file and add the below entry:
mayur:x:502:502::/home/mayur:/usr/bin/git-shell
Please see #1 in Issues to know more why this is needed.

7) Get openssh server up and running on the server hosting the git repositories.
Yum install openssh-server
/etc/init.d/sshd    [status/start]

8) Git setup on client boxes
8.1 ) Make sure that the same version of git is installed on all systems that try to push the code on to the central git repository.
8.2 ) Set up .gitconfig on all developer boxes. We could provide a shell script to them to set .gitconfig values, particularly username and email.

Issues :

1. User would be able to ssh on to the server now . Disabling login with “/sbin/nologin” in /etc/passwd doesn't work as we get the following error that's spewed by the shell.
fatal: protocol error: bad line length character: This
The above issue was fixed with step#6 described above. Please read.

2. If you are on windows and trying to do a xbased port forwarding for gitk, you may have to
- Install tk on linux box i.e., “yum install tk”
- Install Xming on windows box and then launch “Xlaunch”
- Setup environment variable, DISPLAY and point it to the windows IP where you want to redirect the O/P to.
Example :
export DISPLAY=10.10.8.7:0.0

3. If you have issues redirecting, you may want to list the linux box’s IP in X0.hosts file in your Xming installation directory. This will unblock this IP from letting Xbased port forwarding happen.

4.Does everything work fine ? If you are seeing issues like below,
Error in startup script:     (default value for "-font" in widget ".___tk_set_palette.button")     invoked from within
You may have to install “yum install dejavu-sans-fonts” on the linux box.


  
Things to do:
1) Set up ssh keys for users instead of a password based authentication. Let them create keys and send it to us(for now).
We can then add it to the ~/authorized_keys file. This way they can push the code from anywhere.

Similar to what we do in gerrit...

Monday 10 March 2014

Very Useful git commands - devised over a period of time

If one wants to see the commits that are in the 'dev' branch that are not in the 'master' branch, we can do dev ^master, or vice versa. Note that the Windows command-line treats ^ as a special character, in which case you'll need to surround ^master in quotes.
$ git log --oneline dev ^master
fg23456 debug flag added
5890bha memory corruption bug fixed
$ git log --oneline master ^dev
945f70c reusing variable
 
List all commits for a specific file
git log —  <path name/file name>
git log –stat <path> so that we can see the impact of each commit on the file.
git log –pretty=oneline HEAD~3…HEAD~7 | sed -s ‘s/^[a-z0-9 ]\{41\}//g’
Undo a commit and redo
$ git commit …
$ git reset –soft HEAD^      (1)
$ edit                        (2)
$ git add ….                (3)
$ git commit -c ORIG_HEAD     (4)
This is most often done when you remembered what you just committed is incomplete, or you misspelled your commit message, or both. Leaves working tree as it was before “reset”.
Make corrections to working tree files.
Stage changes for commit.
“reset” copies the old head to .git/ORIG_HEAD; redo the commit by starting with its log message. If you do not need to edit the message further, you can give -C option instead
Untrack a directory/file w/o actually deleting it
Th e following will cause git to untrack your directory and all files under it without actually deleting them:
git rm -r –cached <your directory>
List all commits for a specific file
git log —  <path name/file name>
git log –stat <path> so that we can see the impact of each commit on the file.
Git tagging and using commit numbers as build #s
Use tags to mark commits with version numbers:
git tag -a v2.5 -m ‘Version 2.5′
Then use the describe command:
git describe –tags –long
This gives you a string of the format:
v2.5-0-deadbeef
^    ^ ^
|    | |
|    | SHA of HEAD
|    |
|    number of commits since last tag
|
last tag
Remove empty directories in git
Suppose you want to remove empty directories in git but wanna make sure what git will delete run
“git clean -fdn ” to confirm then run git clean -fd to delete the untracked directories.
Create dummy commits in git
Sometimes you may just want to create a dummy commit in the git without actually adding or modifying files.
git commit –allow-empty -m ‘Dummy commit to create the first tag in UI code ‘

Rename a tag in git
I wanted to apply the same tag name to two diffrent branches in the same repository  but git doesn’t allow that.
so I prepended the tag names with a string like MYSQL,MSSQL,ORACLE and it worked
git tag “MSSQL_2.30.0″ “2.30.0″ -f -m “Prepending DB type to the existing tag name”
usage :
git tag <new_tag> <old_tag> -f -m <message>
-f is for forceful renaming
svn -v equivalent for git
SVN’s log has a “-v” mode that outputs filenames of files changed in
each commit, like so:Try one of the following, as git equivalent:git log –name-status
or
git log –name-only
or
git log –stat
To check git messages between two commits/sha1s
git log –pretty=oneline HEAD~3…HEAD~7 | sed -s ‘s/^[a-z0-9 ]\{41\}//g’
we are stripping the sha1 with sed here.
Switch to a new branch
How to switch to a different branch in your repository when you actually cloned a branch (with -b option)
git checkout -b <new_branch_name> remotes/origin/<remote_branch>
eg:
git checkout -b graham_2.30_STABLE remotes/origin/graham_2.30_STABLE
How to check list of files with conflict in git. This is needed while merging.1) git diff –name-only –diff-filter=M
2) grep -rH ‘<<<<<<< HEAD’ * | grep -v .git | cut -f1 -d : | sort | uniq
where
  M: modification of the contents or mode of a file
Other possible values are :
A: addition of a file
C: copy of a file into a new one
D: deletion of a file
R: renaming of a file
T: change in the type of the file
U: file is unmerged (you must complete the merge before it can be committed)
X: “unknown” change type (most probably a bug, please report it)
Omit those commits from  master which are in staging(even the ones which have been cherry-picked) or are patch-equivalent to a commit in staging
git log staging…master –cherry-pick –right-only –no-merges
 

Monday 3 March 2014

Install Git's manual pages

This is for you if you 

- Have downloaded the latest tarball of git manual pages and wish to install it to learn more about the latest exciting stuff in the released git version.

- Have compiled git's source code from scratch, installed it and now wish to install the relevant manual pages that have come with the source so that you know what you have in your git armoury.


Assuming you have source, how to generate the git manual pages and install them on your linux box.
Run:

Run the target "dist-doc" to generate the manual page in the following way:
# make dist-doc

Above will create a tarball of manual pages that will contain the following directories :
man1,man5 and man7

You can obtain this information if you hack the Makefile. Copying an excerpt of the target code below:

manpages = git-manpages-$(GIT_VERSION)  # This is what your git manual pages tarball will be named as
dist-doc:
        $(RM) -r .doc-tmp-dir
        mkdir .doc-tmp-dir
        $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc
        cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar .
        gzip -n -9 -f $(htmldocs).tar
        :
        $(RM) -r .doc-tmp-dir
        mkdir -p .doc-tmp-dir/man1 .doc-tmp-dir/man5 .doc-tmp-dir/man7
        $(MAKE) -C Documentation DESTDIR=./ \
                man1dir=../.doc-tmp-dir/man1 \
                man5dir=../.doc-tmp-dir/man5 \
                man7dir=../.doc-tmp-dir/man7 \
                install
        cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar .
        gzip -n -9 -f $(manpages).tar
        $(RM) -r .doc-tmp-dir


Now to install it,
# sudo tar -xzvf git-manpages-1.9.0.tar.gz -C /usr/local/share/man

With above, I have installed teh manual pages in  /usr/local/share/man. git-manpages-1.9.0.tar.gz was the tarball in my case and may differ depending upon the version you compiled and want to install.

Verification :

Now, how do you verify if the latest manual pages are installed or not:
Hmm, Run this:
# git --version
Check the version that shows up

Now, open a manual page for any of the git commands. Example:
# git checkout --help
Scroll down this manual page and look on the bottom left . Git's version is displayed there.
It should match what you obtained earlier with "git --version".