Posterous theme by Cory Watilo

Filed under: Git

Moving your global .gitconfig file

I am using msysgit for my Git work on Windows and for quite a while I have been wanting to move the global .gitconfig file from its default location into my dropbox folder. The reason for this is probably obvious, I do not want to have to make the same configuration changes on multiple machines to get a homogenize Git environment.

So I set out to resolve this but despite numerous stops at my local Google page, I was unable to find any information on how to make Git look for the file in a different location, it always went to look for the file at %USERPROFILE%\.gitconfig.

As a last resort I asked Joshua Flanagan if he had any idea on how I could configure Git or msysgit to make this possible. Unfortunately he had no idea, but he did however suggest that I try using mklink, a command line utility available in Windows Vista and later.

mklink enables you to create either symbolic or hard links for files or directories. What I needed was a symbolic link, which simply explained is like a shortcut to a file but the difference is that the file system will resolve the symbolic link to the real file, where as a windows shortcut is a file with information in it.

To create a symbolic link for your .gitconfig file do the following

  1. Copy your .gitconfig file from the %USERPROFILE% directory, to the directory where you want to store it instead
  2. Delete the .gitconfig file in the %USERPROFILE% directory
  3. Start cmd.exe as Administrator
  4. Enter mklink .gitconfig path\to\your\.gitconfig (notice the actual filename needs to be in the second parameter or you will link to the folder it is stored in)

You should now get a message that a symbolic link was created between the two files. Try making a change in either of them and see that the change is reflected in the other one – this is because you are always editing the same file since the file system resolves the symbolic link into the real file.

Git staging area – going from being annoying to being awesome

I have been using subversion for a very long time to manage my project and for the past year my interest in Git has grown more and more. A while back we made the decision to move MefContrib and not to long ago we finally got the opportunity to make the move.

Most version control systems have two placers where your code can exist; the working copy or in the repository. However, with Git there is a things option known as the staging area (also sometimes referred to as the Index) that changes the game a bit. You can think of it as a loading area where you can collect things from your working copy that should be sent of to the repository. If you are like me then you are probably thinking “Well, pretty much all version control systems lets me choose what to commit and what not to commit – so what is the point?”.

The point is that the staging area adds even more awesomeness into equation. One of thing (but not only limited to) Git enables you to do with the help of the staging area is to pick individual hunks, from a file, and put them into the staging area while others are left out. If you did not quite get that, it means you can pick and choose exactly what modifications of a file you want to commit to the repository and which you want to hold on for a while longer – partial commits!

To use this feature you simply use the -p a switch on the git add command. However, while I am going to show you how to use this I want to show you how to do it by using the Interactive Adding feature of the git add command. Let us start of by taking a look at a simple sample repository

Staging [master +0 ~1 -0]> git status# On branch master# Changed but not updated:#   (use "git add <file>..." to update what will be committed)#   (use "git checkout -- <file>..." to discard changes in working directory)##       modified:   LICENSE.txt#no changes added to commit (use "git add" and/or "git commit -a")

We can see that there is one file that has had modifications made to it, the LICENSE.txt file. Like the help message says, we can now use the git add command to stage this file for a commit, or use the git commit –a shortcut to stage and commit in one command. But I said I wanted to show how to use the interactive adding feature of Git, so let us instead use the –i switch on the git add command to get started.

Staging [master +0 ~1 -0]> git add -istaged     unstaged path1:    unchanged        +2/-1 LICENSE.txt*** Commands ***1: status       2: update       3: revert       4: add untracked5: patch        6: diff         7: quit         8: helpWhat now>

This brings up the interactive adding menu. Here we can see the status of each file (in this case we only have one file) a long with a list of commands at the bottom. If you look closely you see what it says that there are two (+2) additions to the file, one remove (-1) and that the file is unstaged. The command we want to use is the patch command, this is the equivalent to the git add –p command. To do this we can either enter 5 or p, either works.

What now> pstaged     unstaged path1:    unchanged        +2/-1 LICENSE.txtPatch update>>

Next up is telling the patch command which files you want to apply the command this. Here you get quite a bit of flexibility and also the ability to change your mind before proceeding with the actual patch operation. Below are the things you can do at this point

  • Enter a single file number, for example 1
  • Enter a list of files, for example 1,2,3
  • Enter a range of files, for example 1-4
  • Enter a mix of the above 1,2,4-6

In our case we just want to run the command on the LICENSE.txt file to we enter a 1

Patch update>> 1staged     unstaged path* 1:    unchanged        +2/-1 LICENSE.txtPatch update>>

We can now see that there is a star (*) next to the LICENSE.txt file, indicating that the command will be applied to this file. At this point we can continue to modify the list of affected file with the entries listed above, but we also have the added ability to remove files from the list by using the same entry options as above but also adding a minus sign in front.

Once we are doing selecting the files we want to run the patch command on, we simply hit enter to get started 

diff --git a/LICENSE.txt b/LICENSE.txtindex ecaa6e9..14dac81 100644--- a/LICENSE.txt+++ b/LICENSE.txt@@ -1,3 +1,4 @@+Added some text beforeThis is some license mumbo jumbo-This is some more stuff\ No newline at end of file+This is some more\ No newline at end of fileStage this hunk [y,n,q,a,d,/,s,e,?]?

What we then get to see if a diff view of the first (and in our case, the only) file in the list, we we can see what there are two modifications to the file. We are now requested to make a decision about staging this hunk, which in this case means the entire file with all of the changed (which is the same as just running git add on it). I promised partial commit and partial commits you shall get!

The last line shows a list of actions we can take at this point. The list y,n,q,a,d,/,s,e,? pretty much looks like a bunch of jibberish the first time you see it so to shine some light on the options we have, simply enter a ? to bring up the description

y - stage this hunkn - do not stage this hunkq - quit, do not stage this hunk nor any of the remaining onesa - stage this and all the remaining hunks in the filed - do not stage this hunk nor any of the remaining hunks in the fileg - select a hunk to go to/ - search for a hunk matching the given regexj - leave this hunk undecided, see next undecided hunkJ - leave this hunk undecided, see next hunkk - leave this hunk undecided, see previous undecided hunkK - leave this hunk undecided, see previous hunks - split the current hunk into smaller hunkse - manually edit the current hunk? - print help

What we want to do is to select which hunks we want to commit and which we want to leave for now. To do this we use the s option, which tells the patch command to split the current hunk into smaller hunks. So let us do that

Stage this hunk [y,n,q,a,d,/,s,e,?]? sSplit into 2 hunks.@@ -1,2 +1,3 @@+Added some text beforeThis is some license mumbo jumboStage this hunk [y,n,q,a,d,/,j,J,g,e,?]

Now one get the option to decide on the first hunk of the file. By entering y we tell Git to stage this hunk for us

Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? y@@ -1,3 +2,5 @@This is some license mumbo jumbo-This is some more stuff\ No newline at end of file+This is some more\ No newline at end of fileStage this hunk [y,n,q,a,d,/,j,J,g,e,?]

It now displays the second hunk along with the same options as before. This time we are going to enter n to tell Git not to stage this hunk. Since this was the last hunk in the file, and we only had one file, we are now brought back to the interactive adding menu.

Enter 1 or  s to run the status command

What now> sstaged     unstaged path1:        +1/-0        +1/-1 LICENSE.txt

We can now see that the license file is both staged and unstaged at the same time! How how cool is this?!

Enter 7 or q to quit the interactive adding command, then run a normal git status

Staging [master +0 ~1 -0 | +0 ~1 -0]> git status# On branch master# Changes to be committed:#   (use "git reset HEAD <file>..." to unstage)##       modified:   LICENSE.txt## Changed but not updated:#   (use "git add <file>..." to update what will be committed)#   (use "git checkout -- <file>..." to discard changes in working directory)##       modified:   LICENSE.txt#

As you can see, the file is also displayed as both staged and unstaged when using the normal status command. Now all that is left to do is to commit the change like you normally would do

Staging [master +0 ~1 -0 | +0 ~1 -0]> git commit -m "Added additional text to the license file"[master 9a89da5] Added additional text to the license file1 files changed, 1 insertions(+), 0 deletions(-)

The change was commit as expected.  Be careful not to use the –am option with the commit command, since it will ignore the staged hunks and commit the entire file, this is because the –a option tells Git to add and commit all tracked files.

Now run a git status to verify that we have uncommited modifications to the LICENSE.txt file

Staging [master +0 ~1 -0]> git status# On branch master# Changed but not updated:#   (use "git add <file>..." to update what will be committed)#   (use "git checkout -- <file>..." to discard changes in working directory)##       modified:   LICENSE.txt#no changes added to commit (use "git add" and/or "git commit -a")

Yep, they are still there and if we want to be really sure we can run the git diff command to see that the modification that we have is the same as the hunk we decided not to stage before

Staging [master +0 ~1 -0]> git diffdiff --git a/LICENSE.txt b/LICENSE.txtindex 0b6cc6c..14dac81 100644--- a/LICENSE.txt+++ b/LICENSE.txt@@ -1,4 +1,4 @@Added some text beforeThis is some license mumbo jumbo-This is some more stuff\ No newline at end of file+This is some more\ No newline at end of file

And that is all there is to it. The Git staging area is more than just a fancy waiting area for files, it brings some powerful features onto the table. There are more things you can do with the staging area but those are way beyond the scope of this