Git Notes

A collection of my Git learnings. I’m VERY familiar with Mercurial but starting to learn Git. No reason other than I’m starting to work with it more, so want to be familiar with what it can do.

This is not intended as a comparison of the 2. The more I do with Git, the more I stand by my initial impressions. Both will allow you to accomplish the same things. It’s more about how to do it in each one.

My opinion is that HG is easier to learn, and better for a team new to DVCS. It supports more advanced workflows, but starts to get in your way.

Once you’re familiar with a DVCS, and want to do advanced things, Git becomes the easier one to work with.

Bottom line: Should you choose HG or Git? YES!!! There are very few cases where a DVCS isn’t a better option than the alternatives.

Getting started

HG to Git Translation

Function Git Mercurial
Retrieve changes from server WITHOUT updating workspace fetch pull
Retrieve changes from server and merge with local changes pull pull then merge or use the fetch extension.
pull -u will update only if you don’t have any local changes
Remove the last changeset, returning changes to working directory. To remove more, increment the ‘1’ in each example. reset HEAD~1 strip -k -1
Remove the last changeset. To remove more, increment the ‘1’ in each example. reset –hard HEAD~1 strip -1
Create a branch and do work on it. git checkout -b <name> hg branch <name>

General workflow

Will incorporate discussion of creating a local branch, doing work on it, remotely tracking it, putting changes onto master (or appropriate branch) once done, and cleaning up remote when done.

Common tasks

Rebase

checkout branch want to rebase and do rebase identifying target branch.

Merge

checkout branch want to merge into and merge identifying branch to merge in.

Deleting branches

To remove a local branch, use the -d option on branch. If you’ve merged the branch, then it will be deleted. If not, then either merge it in, or use -D to force a delete of the branch.

To remove a remote branch that has been pushed, delete the local branch, and then remove the remote branch by pushing the now non-existant branch to the remote. The command is `git push origin :refs/heads/{branch_name}. This will delete the remote branch.

Update current working directory to another location

Can update to any changeset using git reset --hard origin/master as an example.

This can be useful if you do a pull with uncommitted changes. If you have uncommitted changes, Git will do a fetch. If you just want to goto the new end of branch, then run

  • cleanup any uncommitted changes
  • git reset –hard origin/master

This will reset the current branch to wherever origin/master currently is.

Move current working directory changes to new head because others have made changes

If you’re not working on a feature branch (which you probably should be), can still fetch others changes with working directory changes, and apply these changes to the head, using merge tools.

  • commit changes – to ensure keep changes around
  • rebase origin/master – rebases the temp changeset onto origin/master (this would be wherever you want to move your changes to). Fix any issues in rebase using your preferred method.
  • reset origin/master – put the temp changeset changes back into the working directory.

Cleaning up unwanted changes

  • Reset entire repo to last committed state:’git reset –hard’. This doesn’t remove untracked files
  • Remove untracked files, directorys:’git clean’. add -d to remove directories, -n to do a dry-run.

Retrieving ‘lost’ changes

If you’re not careful, you can appear to lose changes. Doing a careless checkout or reset –HARD can move you to a location, leaving some changesets with no connection to existing code.

git reflog is your friend. It keeps track of where you’ve been, and allows you to recover lost items. Reflog will show the previous locations of HEAD, and should have some sort of message that indicates where you did a hard relocate and left orphaned changesets.

Doing a git reset –HARD back should restore the changes.

Restoring deleted file

Stackoverflow link

Many useful examples on that post. Bottom line, find out which commit deleted the file, and then do a git checkout {commit}~1 {filename} to retrieve it. The ~1 is short form for ‘commit before this one’.

Removing commits, possibly keeping changes from commit

Many useful options at Stackoverflow question#927358

Basically, have 3 options

  • Delete commit: git reset --hard HEAD~1
  • Remove commit. Return changed files to workspace: git reset HEAD~1
  • Remove commit. Return changed files to workspace and keep index as is: git reset --soft HEAD~1

Useful configuration

git config –global will set the configuration ‘globally’. i.e. it will be set for all repos unless overridden locally. –local sets it for the specific repo only

Set username and email

  • git config --global user.name=name
  • git config --global user.email=email address

Create helpful aliases for commands

Below is an excerpt from the ~/.gitconfig file. Aliases can be defined globally either by modifying the .gitconfig file manually, or using git config --global command.

To define an alias using the command line, use git config --global alias.{alias} {definition}

Fix whitespace issues when applying a patch

‘git config –global apply.whitespace fix’

Define an editor other than the default one

git config --global core.editor "{editor command string}".

One thing to be aware of. Git will continue as soon as the editor provides an exit signal. Here are a couple examples to work around this.

  • gedit on ubuntu. Use gedit -w -s which tells gedit to run standalone (in case it’s already running) and to hold the process until it exits.
  • notepad++ on windows. Use notepad++ -multiInst -notabbar -nosession -noPlugin. Tells notepad++ not to save a session, no tabbar, no plugins, and to start a new instance.

Convert Mercurial (HG) to Git

Instead of using hggit you may use hg-fast-export.

  1. Create new git repo on remote server.
  2. git clone git://repo.or.cz/fast-export.git
  3. mkdir newgitrepo
  4. cd newgitrepo
  5. git init
  6. /path/to/hg-fast-export.sh -r /path/to/hg_repo
  7. git checkout HEAD
  8. git remote add origin {remote server git path}
  9. git push origin master

Appears hg-git introduces its own changesets into the stream…

Patches

Patch tutorial

Summary:If all patches in a branch, simplifies process.

‘git format-patch master –stdout > patchName.patch.

This will extract all changes on current branch from master branch. If want changes relative to another branch, change the master to something else.

To apply patch:

  • Check what patch will do: ‘git apply –stat patchName.patch
  • Test patch: ‘git apply –check patchName.patch
  • Apply patch:’git apply patchName.patch’.
  • If you want it signed because it’s a patch from someone else, use ‘git am –signoff < patchName.patch’, and signed-off-by metadata will be added to the commit message.

If get whitespace issues, can remove patch, and turn on apply.whitespace fix to config

Interactive Staging

One can obviously use the command-line tools, but I find some things easier to do with a GUI. git gui is very helpful for doing this. Allows one to see differences, and move lines/hunks quickly from/to staging.

Mimic incoming and outgoing

Haven’t gotten this working correctly just yet, but once figure it out, will update.
From Stack Overflow question

Starting with Git 1.7.0, there is a special syntax that allows you to generically refer to the upstream branch: @{u} or @{upstream}.

To mimic hg incoming:

git log ..@{u}
To mimic hg outgoing:

git log @{u}..
I use the following incoming and outgoing aliases to make the above easier to use:

git config –global alias.incoming ‘!git remote update -p; git log ..@{u}’
git config –global alias.outgoing ‘log @{u}..’
share|edit|flag
answered Jun 17 ’11 at 17:18

Richard Hansen
4,0431123

git log ..@{u} gives me these errors. (I have both origin and an upstream repository in my git config). error: No upstream branch found for ” error: No upstream branch found for ‘..’ error: No upstream branch found for ‘..’ fatal: ambiguous argument ‘..@{u}’: unknown revision or path not in the working tree. Use ‘–‘ to separate paths from revisions – hced Oct 1 ’11 at 13:42

You’ll get those errors if your local branch isn’t configured with an upstream. To fix, run git branch –set-upstream foo origin/foo. – Richard Hansen Oct 1 ’11 at 18:18
upvote
flag
worked well for me, cheers – Mark Simpson Feb 10 at 11:37

Git on Windows

If you’re using windows, then install Git from the main git page. This will also install git-bash, but if you don’t want to work with a unix like command-line, consider using Powershell 2.0. There are a couple of handy items to help out. One for some command prompt changes that acknowledge git, and another for using ssh-agent.