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
matt@prod$ cd where-the-repo-is
matt@prod$ git pull origin 3.5.1
matt@prod$ 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.
Add New Comment
Viewing 3 Comments
Thanks. Your comment is awaiting approval by a moderator.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Add New Comment