M-x Kelsin

git

Tag: git

Git SVN Recovery

Recently at work I had to checkout a repository that I was previously syncing to an SVN repo. It turns out the SVN history is kept in the commits so I just needed a way to convince git-svn that the current master branch was in fact linked to the SVN repo’s head.

Global GitIgnore

A couple of days ago I used the github guide to setup a global git ignore file. Today I realized that it wasn’t working at work. The command version of git config used an absolute path to the file when using a ~ relative file works perfectly fine.

Finding lost commits

git fsck --full --no-reflogs | grep commit

Git Home Directory

I’m installing some dev stuff onto my windows box and finally want to document how to get a new home directory installed:

Heroku Config Variables

Deploying on Heroku is such a breeze! I love the way they take care of my database.yml file so I can just keep a clean version in my open source repo!

Git Tech Talk

We’ve started up doing Tuesday Tech Talks at work and I got to go first by talking about git. We use git to store all of the code I work with. For the people working directly with me this was mostly review. The rest of the co-workers span the gammit on knowledge. For this reason I tried to go pretty low level in some cases, and also span a huge list of topics. My main goal is that sometime in the future, when they are using git, they will think of one part of my presentation and look up the needed info to implement or incorporate that idea into their work. Whether it’s as simple as rebasing to clean up their code before commiting it to a dev branch, or adding the git branch name to their prompt.

Updated Git branch in bash prompt

I had my git branch showing in my bash prompt for a long time. I recently changed my code around to make it much faster (more info below). Here are all the steps to go through.

Bash Completion

The first step is to get bash completion installed and install the git files for this as well. I use homebrew on the mac to install most open source stuff so you can just install bash-completion from that:

brew install bash-completion

At the end of the install it tells you to do some things… Do them:

Add the following lines to your ~/.bash_profile file:  if [ -f `brew --prefix`/etc/bash_completion ]; then    . `brew --prefix`/etc/bash_completion  fiTo install Homebrew's own completion script:  ln "#{HOMEBREW_PREFIX}/Library/Contributions/brew_bash_completion.sh" "#{etc}/bash_completion.d"

After this you can install git:

brew install git

and it will install the git prompt functions as well. You can try running __git_ps1 from inside a git working directory (in a new shell) to check that it’s working correctly

Adding branch to prompt

If you just want to add the git branch to your prompt you can just use __git_ps1 in your prompt. There’s a lot of details in the git completion file. It’s located at /usr/local/etc/bash_completion.d/git-completion.bash in a standard install of homebrew.

My prompt

I wanted my branch to change color based on if I’m root or not, if I’m on a remote machine or not and I want the branch color to change based on the git status. I did all this via some really messy shell code before. Recently git added support for some git status information in the git_ps1 output (but not using colors) so I rewrote my code using the same methods they had for determining git status. This was all stuff I could have done before but I’ve never looked into fancy git commands like diff-index and rev-parse before. My current_version of my prompt file is pretty great and ends up much faster.

Rewriting Commit History

Recently at work I was working on a small bug fix git branch that had MANY small commits doing relatively the same thing. I really wanted to go through and clean up the commit messages to make them uniform and actually needed to change some of the commits too.

By google searching I found this stack overflow question that gave me my answer. This user wrote about how using rebase –interactive can be used to specify any number of commits to edit. You basically call git rebase --interactive COMMIT where COMMIT can be HEAD^ to just do one commit, or any SHA1 or branch reference as normal. Git will open your $EDITOR with a file listens all commits in question. You can then edit this temporary file to tell git what commits to let you edit and which ones to drop completely or merge into the commit above them (which you can do manually via edit as well). Then git will play through your commits that you’ve said you want to edit one at a time, and drop you into a shell to let you do anything you want. Sometimes you want to edit just the commit message so you just git commit --amend and change the message. Other times you want to undo the last two commits and redo them git reset HEAD^^ and then edit and commit again.

Also just to remember this (recently discussed at work as well):

<ul>
  • git reset HEAD^ undoes the last commit and places changes as changes in the working tree.
  • <li><code>git reset --hard HEAD^</code> removes the commit changes completely (not form the git data store, but completely from your working tree at least)</li>
    
    
    
    <li><code>git reset --soft HEAD^</code> puts the changes into a "staged" state. This makes it east to add to a commit while you have many other edited files in your tree (Maybe even more changes to a changed file that you don't want to add into this commit)</li></ul>
    

    Git Ignoring already committed (tracked) files

    In my current local development environment for work I don’t have access to our authentication mechanism. Our rails site uses a cookie from our main site. In order to ignore this I commonly edit my controllers with a line like:

    
    self.current_user = User.find(5)
    
    

    (This is just a snippet and doesn’t include the code that allows for the current_user method, this post is NOT about authentication in rails). This allows me to just work on features without having to do some complicated cookie copying and other stuff I’d rather not mess with.

    I use magit on emacs to do my git management and I hate seeing that this controller has a change in it (same with using “git-status”). I don’t want to accidentally commit this change either. The simple answer to this is to tell git to mark this file as “not changed”. I found this post that told me about this feature. This feature exists in order to help people with slow filesystems but it works great for this use as well:

    
    git update-index --assume-unchanged path/to/file

    Now the files don’t show up in any status commands or when I commit with “git commit -a”. These files will cause git to gracefully error when merging in a branch that changes these files (so you can manually handle it) and it will remove this flag if you manually “git add” these individual files.

    The problem I ran into is that I want an easy way to check what files are setup like this. I couldn’t find a git command to do this already so I added these aliases:

    
    [alias]
    
        marked-unchanged = !git ls-files -v | grep ^[a-z]
    
        mu = !git ls-files -v | grep ^[a-z]
    
    

    Now both “git marked-unchanged” and “git mu” show me a list of files that are set this way so I don’t forget. I want to add magit commands to show this and set this as well but that will be another day and another post.

    Git Push Defaults

    Recently I’ve began working locally on my macbook and have installed git 1.6 from the binary package. I haven’t noticed anything different from my work servers (v1.5) and my new 1.6 locally except for push defaults. Git likes showing this huge warning about how you can change the way push works now. It does the same thing as it has done previously, just with a giant message about how you can change it if you want.

    I found more information about this here: git config push.default matching

    After reading that helpful post I decided to set my git config globally:

    
    git config --global push.default tracking
    
    

    If anyone knows more about this stuff I’d love to hear opinions about tracking vs current. Basically I’ve pushed things I haven’t wanted to push yet with the default “matching” option. I like most git operations to only function on my current branch (especially when dealing with pushing). Current seems to provide that but it will push the current branch to “a branch of the same name” according to the man page of git-config. Tracking says it pushes the current branch “to its upstream branch” which seems more correct to me since I might have tracking branches with different names. I’m hoping that git will complain if I call git push with no arguments on a branch that isn’t tracking a remote branch.

    Git Home Directory

    This is just a quicky but I had to setup a new laptop and remembered how easy it is to install a new git home directory into a clean Mac OS X home directory. I’m using the Mac OS X git binaries gotten from http://code.google.com/p/git-osx-installer/downloads/list?can=3 (also linked from the main git site).

    From my home directory on the new mac:

    git init
    
    git remote add origin username@repo
    
    git config branch.master.remote origin
    
    git config branch.master.merge refs/heads/master
    
    git pull

    Obviously replace the username@repo with your home directory repository. For me I get no conflicts at the moment. Not sure what would happen if there are conflicts, but it’s nice that git just adds the new files and any files that are the same just stay. Pretty awesome.