When I switched to git from subversion at my old business, I stored notes on how to do certain tasks. I’m pasting it below. Maybe some of this will help you out.

If you know a better way to do these tricks, please let me now.



My git diary

============

.. contents::

Slowly learning how to use git.

Typical upgrade flow

--------------------

I just committed a bunch of code and I want to see what the diffs were,

so I ran this::

$ git diff HEAD^

My production server runs branch 3.5.1 of my software. I want to start

work on a scary new feature that may take a long time, so I made a new

branch called 3.5.2 in my local sandbox::

$ git checkout -b 3.5.2

Now I can commit all my intermediate stuff in here.

Somebody found a bug in the production site (running 3.5.1) so I switch

to my 3.5.1 checkout::

$ git checkout 3.5.1

$ vi # fixing the problem

$ git commit -a -m "Fixed the prod bug"

$ git push origin 3.5.1

That last line sends my local commits to my remote bare repository.

That remote bare repository is on a box with an SSH server and RAID

storage.

Then I connect to the production box and pull down the most recent

changes::

$ ssh prod

[email protected]$ cd where-the-repo-is

[email protected]$ git pull origin 3.5.1

[email protected]$ restart-everything

That restart-everything command is a homemade script that does just what

you think it does.

Now back in my dev sandbox, I want to pull the bug fix from 3.5.1 into

my 3.5.2 branch. So I do it like this::

$ git checkout 3.5.2

$ git pull . 3.5.1

And now my 3.5.2 branch has that code in it. Hurray! Understand that

the dot (.) in git pull . 3.5.1 means that git should retrieve code from

this repository, not the fancypants remote one.

Pulling stuff

-------------

When I run::

$ git pull origin 3.5.1

That means to pull from the origin's 3.5.1 branch into whatever branch I

currently have checked out.

A typical day

-------------

I have two branches, an experimental branch and a public branch.

The production server used by customer runs the public branch.

Usually I work in my development branch. Sometimes I have to do some

code into production so this is how I do it::

$ git checkout stable # switch my local copy to the stable branch.

$ git pull origin stable # update local copy, just in case.

$ vi blah.py # do the bug fixes.

$ git commit -a -m "Notes about bug fixes"

$ git push origin # This is my deploy system.

$ git checkout dev # Go back to my development branch.

$ git pull origin stable # merge in that bug fix.

So far, this works well. I did something similar with SVN, and it also

worked fine. But git is way better at safely merging and it is much

faster.

Undo changes to a single file

-----------------------------

I typically edit a dozen files and then figure out that I want to undo

some stuff. If I did::

$ git reset --hard

Then my whole working copy would be destroyed. Usually, I just want to

do something like revert one file. So this is how::

$ git checkout that/particular/file

That deletes my working-copy changes just there. Everything else is

left as-is.

How to submit patches by email

------------------------------

I cloned the ditz project and tweaked the code, and I wanted to submit a

patch, so this is what they told me to do::

For this type of thing, it's "very simple". git commit -a, add a

one-line description followed by a blank line and more commentary, and

then git format-patch HEAD^.

When I ran git format-patch HEAD^, that produced a file on my local

machine that had a pretty formatted patch. Then I emailed that patch to

the list with some text.

How to branch from a remote repository

--------------------------------------

This is what somebody in the #git room told me to do, since I use a

remote bare repository::

$ git fetch origin

$ git checkout -b newbranch origin/original

Here's another person's opinion::

$ git fetch && git checkout --track -b mynewbranchagain remotename/mynewbranch

Set the remote branch

---------------------

Normally I have to pull from my remote repo and specify the branch I

want to pull in like this::

$ git checkout experimental

$ git pull origin experimental

It is possible to associate my local branch of experimental with that

remote branch of experimental like this::

$ git config --add branch.experimental.remote origin

$ git config --add branch.experimental.merge experimental

And now I can run::

$ git pull origin

without specifying the remote branch. In fact this works too::

$ git pull

Compare one file across two local branches

------------------------------------------

I want to look at a diff of x.py in my public branch vs my experimental

branch, so this is what I did::

$ git diff public experimental -- x.py

I can see everything different between the two branches like this::

$ git diff public experimental

Break up a whole bunch of changes into different commits

--------------------------------------------------------

I'm irresponsible about committing after each conceptual unit of work.

Lots of time, I'll edit a file to fix one bug, then while I'm in there,

I'll edit some other code because I see a better way to do something

else. Then I'll maybe add a few doctests to a completely different

section just because I want to.

After a few hours, typically inside of the same file, I have edits

related to multiple separate tasks.

Before I commit my changes, I run::

$ git add -p frob.py

Which walks through all the changes in that file and asks me if I want

to stage each one. In the first pass, I stage all the hunks related to

the first issue. Then I commit those changes. Then I rerun git add -p

frob.py again and march through the file for the next the second issue.

Keep in mind that I committed my changes after the first pass, so when I

go through the file the second time, I won't get prompted for those

changes.

This is one of those git features that you just couldn't do with svn.

Find the commits in branch A that are not in branch B

-----------------------------------------------------

Sometimes I'll patch a production bug in my production branch and then I

will forget to merge it into the development branch. This is how I can

check for that::

$ git checkout production_branch

$ git cherry dev_branch

This will spit out a list of commits that are in production_branch but

not in dev_branch.

It will not return any commits made to dev_branch but not in

production_branch.

See a file as of a point in time

--------------------------------

Looking at a commit shows the changes. Sometimes I want to see the file

itself.

Here's how to look at foo.py as of two commits ago::

$ git show HEAD^^:b/foo.py

Here's how to see what foo.py looked as of a particular commit::

$ git show bf51ebdbc:b/foo.py

b/foo.py is the path to the foo.py from the top of the repository. I'm

not certain, but I don't think the current working directory matters.

Copy a file from one branch to another

--------------------------------------

I committed a file into one branch then checked out a new branch. This

is how I copied that file into the new branch WITHOUT merging it in::

$ git checkout newbranch # 1

$ git checkout otherbranch foo.py # 2

Step 1 moves me into the newbranch. Step 2 gets me a copy of the file

foo.py from otherbranch and saves it into this branch named newbranch.

See a file in a different branch

--------------------------------

After I checkout the maxhenry branch I want to see the version of

printable.kid in the mayfield branch::

$ git checkout maxhenry

$ git show mayfield:bazman/bazman/templates/printable/printable.kid

Set a file to an old version of itself

--------------------------------------

Sometimes I want to get the version of a file as of a certain commit and

check that in. There are lots of ways to do this, including using git

revert or git reset, but I've had good luck with this approach::

$ git log # Use this to find the commit you want.

$ git checkout ac778cbb5517e1aeef446c9a8a1092eef81717fa:repo-top/a/foo.py

After you run this, the index will have this old copy queued up to be

commited. You can use git diff --cached to see the changes.

Create a new branch on the remote repo

--------------------------------------

We just pushed the branch **mollusk** up to production, so now it is

time to create a new branch named **nosehair**::

$ git branch nosehair # creates the new branch

$ git checkout nosehair # switches to the new branch

$ git push origin nosehair # pushes it up to origin

Switch to a new branch that already exists on a remote repo

-----------------------------------------------------------

After somebody else already created the branch nosehair, and pushed it

up to the remote repository, here's how to switch to work on the

nosehair branch::

$ git fetch origin

$ git branch -a # make sure origin/nosehair exists!

$ git checkout -b nosehair origin/nosehair

Search through commit messages

------------------------------

This is how I found all commits that had a commit message that included

the word CCPL::

$ git log --grep=CCPL

This is how I limited it to just my (Matt's) commits for CCPL work::

$ git log --grep=CCPL --author=matt --all-match

Without the --all-match option, you'll see all commits by matt or that

have CCPL in the commit message.