Skip to content

Latest commit

 

History

History
328 lines (169 loc) · 14.7 KB

learning_git.md

File metadata and controls

328 lines (169 loc) · 14.7 KB
path title
/learnings/git
Learnings: Git

Git is pretty neat, and lets you think about source code management in totally different ways. Go Git!

Git Nouns and verbs

Nouns

clone / checkout / repository

a complete (approximately) copy of the repository on your local machine.

This is disconnected with the server's version of the repository until you push or pull

remote

A remote copy of the code, on something that behaves like a server. (Github, Bitbucket, or a machine you have git ssh into to store changes. Git is super scale-downable.)

Can be named whatever, but by default your first remote is named "origin".

branch

These are easy to ceate. Unlike subversion Git does not use the file system to store different branches, and because everything is distributed you ca create a branch on your local machine, and it doesn't exist anyhere else (until you push it)

commit

Commit. These are also easy to create and commits can exist just on your local machine. Because of thi I like to make my Git commits very small. I like to aim for my commits to feel like a single thought: almost a sentence, as if it was code.

Does this commit do one thing? No, seriously, one thing. I may write some code for a ticket or task and break it up into 5 or 6 seperate commit yjust committing the right parts. Theres a bit of an art form here, and also it might not matter if you squash your merges, but it makes me feel good.

In Git commit numbers are SHA1 summaries of the content (they are not sequential ie as in Subversion or CVS). Additionally, in most cases only the first 7 characters of a SHA-1 matter to uniquely identify a commit (unless you're the Linux kernel, which needs 8 due to the sheer size of the codebase).

Stage

Unlike Subverion, the whole woking copy is not automatically included in a commit. You have to add files to the stage, then commit them.

Some Git UIs may ignore parts of this, but because o how it work (splittig work into sentences) I see this as a feature, not a bug.

Git doesn't work on just a file level: you can stage indidivual parts or lines of a file. SourceTree does this really well, the git CLI you have to be clever about.

Verbs

Push / Pull

Push: send the code you have to the server

Pull: pull the code on the server down to you.

If you are pushing a feature on a branch you are working on with a friend, and they have committed to the repository, you'll need to pull to get their changes. If that happens and you have changes on your end, Git will probably figure out the merge and do it corectly (unless you literally change the same lines). Only then can you push your changes to the remote.

Fetch

download all the branches from the remote repository. Usually not required, but if you get an error from git about it can't checkout a branch you know exists, do a fit fetch.

Stash

puts all your changes in a temorpary holding area, and clears the working directory. This may allow you to switch branches when you for example realize that some of your work belongs in another branch.

Merge a branch

There's a couple different ways you can do this. One can set it up so that merges of pull requests will condense all the commits in your pull request into one, clearly labelled, commit. This is called a squash merge.

See also:

Git Branches (and stuff)

Remote Branches

$ git checkout -b BRANCH_NAME_THAT_YOU_WANT_LOCALLY --track origin/REMOTE_BRANCH_NAME

Which will pull down the remote branch (found at origin/REMOTE_BRANCH_NAME) into the locally named branch BRANCH_NAME_THAT_YOU_WANT_LOCALLY.

(Technically there's nothing special about origin - it's just the name of the remote tracking branch you're using. This is explained later...)

Then git pull to get the code...

"Take a mod from that branch and put it over here"

(aka: pull a commit from the trunk into a release branch)

Use git-cherry-pick to "Cherry-pick" ''just'' one commit out of a branch to put it in the current checkout:

$ git cherry-pick -n SHA1

(Replace SHA1 with the SHA1 hash for that commit you see in git log)

When you're feeling confident you can remove the -n training wheels. That just says "Do not automatically commit the cherry pick".

"Push this work up to the branch"

Now your work is on your local machine, but you have to move it up to the remote server's branch.

$ git push origin BRANCH_NAME_THAT_YOU_HAVE_LOCALLY:REMOTE_BRANCH_NAME

By default a "git push origin" command will post your changes up to the remote server to origin/BRANCH_NAME_THAT_YOU_HAVE_LOCALLY, which you might not want. So we add the LOCAL:REMOTE parameter to explicitly state what branch it goes to remotely (neither LOCAL nor REMOTE parameters need origin/. If your remote branch is origin/release1.0, all you need is the release1.0 part)

"Make a copy of the current checked out branch up on the server, and name it..."

You want to make a new branch

$ git push origin BRANCH_NAME:NEW_BRANCH_NAME

Remote related error messages

$ git push origin BRANCHNAME
ksh: git-receive-pack: not found

This error is caused by the current machine (the push-er) not being able to access git-receive-pack on the remote machine (the pushed-to) because git-receive-pack isn't on the PATH for the user the client logs in under.

'''Solution''': figure out what the path for git-receive-pack on that remote machine and give it to git explicitly like so:

$ git push origin BRANCHNAME --receive-pack=/opt/local/bin/git-receive-pack
....


$ git checkout -b wreal_soft_launch_2008121 --track origin/soft_launch_2008121
fatal: git checkout: updating paths is incompatible with switching branches/forcing
Did you intend to checkout 'origin/soft_launch_2008121' which can not be resolved as commit?

'''Solution''':

$ git fetch

I think this problem is related to git not having the remote branch names on hand, so a git fetch gets those and lets you check them out... I think

See also: [http://www.skrinakcreative.com/wp/?p=175 This problem at skrinakcreative]

Normal Branches

Pulling changes in the master up into your current branch (in your branch):

$ git rebase master

Pulling changes in the branch to the master (from the trunk/master branch)

$ git merge branchname

You can create a git branch on top of a dirty working copy and have a branch created with those (dirty) changes.

Understanding git commands

From Remotes (aka: remote tracking branches)

Commands like git-pull and git-push are in the following format:

$ git-pull REMOTE-NAME BRANCH-NAME

When you clone a git repo, git-clone actually creates a remote tracking branch (named "origin", by default) and checks out the initial branch equal to the remote's currently active branch. (http://www.kernel.org/pub/software/scm/git/docs/git-clone.html Reference) (Yes, this is dense English). BUT you can use git-clone -o NAME ... to override the default NAME of "origin". Or you can let git-clone to its thing and edit .git/config yourself with the new name.

By default git-pull and git-push know what remote tracking branch you're on now, and what regular branch, but if you want to be pedantic (or want to override something for some reason) that is the syntax. See the "pushing your changes up to Git-hub" section for an example.

But these optional parameters mean you can be tracking '''many''' remote branches at one time... like tracking the main git remote branch, and also a (say) remote branch on your desktop machine for the work you've done there but not pushed up to the main remote branch yet.

Oft Used Git Commands

  • git stash / git stash apply <-- "get my unsaved changes out of the way, so I can push or pull/OK, put my changes back"
  • git checkout FILE <-- will revert any modifications to FILE made since the last commit (so it's like svn revert FILE)

Git via Email

Git is distributed - which means there doesn't have to be one centralized server. One (very low-tech, but very simple) way to do this to just email git diffs back and forth - telling people exactly what you changed in one commit (or a series of commits, or whatever). Which might just be Good Enough For Right Now... or good enough for your situation.

To package your changes up:

$ git commit                              #commit your changes to the repo
$ git-format-patch HEAD^    

The git-format-patch command says ("package the differences from the last revision to HEAD up in mailbox-style format). (Check out the rubinius link below for what the ^ means)

Now send your email away

On the receiver side:

$ git-am MAILBOX_FILE_YOU_GOT_VIA_EMAIL

Which imports the commit you got via the mail... and commits it to your repo. It'll look (in git-log) like ''they'' made the commit!

Thanks to the [http://rubinius.lighthouseapp.com/projects/5089/using-git Rubinius documentation on git] for help with git-format-commit!

NOTE: I wouldn't do this for any real length of time, nor with more than say 2 developers... but it might just keep your dev team truck'n when the central server dies.

If Your Patch Doesn't Apply

If errors about whitespace, see this blog article

GIT-SVN

git-svn is our preferred way to use Subversion

Handling svn:externals with git-svn

git-svn doesn't have native support for svn:externals. But there are a number of third-party tools to fill the gap:

  • git-svn-clone-externals It makes you put the checking scripts in the same folders as the externals (making it a PITA that way), BUT it includes nice utility scripts that check to see if you have any unpushed changes/uncommitted changes OR if your externals are out of date.
  • git_svn_externals Has differences from the above script in the following ways: (1) will recurse the directory and find folders with svn:external properties (instead of needing you to place the script correctly) (2) will update all these external repositories when ran at the top level directory again and (3) is compatible (similar directory structure and approach) to the git-svn-clone-externals script above (meaning you can use the more advanced git-svn-check-unpushed and git-svn-externals-check scripts from the former.
  • gsc Python utility that does the same. Disadvantage is that it bakes in assumptions about trunk/branches/tags, which may not always be the case with my projects.

Including branches and trunk too (standard SVN layout)

SVN Branches in git. In a nutshell: tell git svn clone where the trunk and branches directory is (or use git svn clone $URL --stdlayout). Then read the article.

Pushing Your Changes

Up To GitHub

$ git diff   
$ git commit -a -s    # -a = sync index and (??) -s = sign off on changes
$ git push origin master # send thosue changes up to github

To a local file system repo

git repositories on local FS

= Git Documentation / Tutorials =

A Git introduction by the CS department at cmu.edu

(some parts specific to their setup, but after the first "installing git" part it's good)

GitMagic is a great bit of git documentation!

Git Guide for SourceMage (in Q&A format)

Handling conflicts in Git

= Useful Third Part Git Tools =

Git-wtf: gives information on how your current repo differs from the remote repo, and the merged state of your branches

Sequential Revision Numbers in Git

Merging

Merging can be, umm, fun.

Reverting a file to your state (premerge) or their state (premerge)

$ git checkout --ours somefile.txt OR $ git checkout --theirs somefile.txt

Super Advanced Git commands (Rewritting history)

Get rebase for picking apart commits explained

git diff with a remote repo

Merging Two Git Repos

Removing a commit in an un-pushed repo

Splitting out mashed up commits that are on another branch

( create your new branch, or get on master or whatever)
$ git cherry-pick -e SHA1
$ git reset HEAD~1

Now you are at a point where you would normally git add files to the commit. Now craft your commit with git add -p or GitX or whatever, and make your commits.

How to move a commit from master to a branch

$ git branch experimenting $ git reset --hard HEAD1 # HEAD1 should be the commit you want to move over

How to cherry-pick a commit from another repo

(Thanks to this blog entry: Using Git To Pull in A Patch From A Single Commit

git fetch REPO branchname #where REPO can be the location of an on-disk repo, or a 'remote' name git cherry-pick SHA1

Doing Git magic on the command line

http://www.elctech.com/tutorials/untangle-your-git-commits-with-git-add---patch how to add individual chunks from command line/interactively

Arild Shirazi said, on this front:

$ git add -p foo
$ git commit foo

is WRONG

the right way to do it

$ git add -p foo
$ git commit

as soon as you specify a directory of file for the commit, it ignores the partial (hunk) to commit, and goes ahead and commits the whole file

Integration/fitting into WDS patterns

Integrating with vimdiff

How to integrate into vimdiff

== Integrating Git information into builds == Git and XCode build script (also has alternative versions and a Hg shell script too!)

Understanding Internals

See also: