$ git count-objects <2>
$ git repack <3>
$ git prune <4>
-
+------------
++
<1> running without "--full" is usually cheap and assures the
repository health reasonably well.
<2> check how many loose objects there are and how much
<3> without "-a" repacks incrementally. repacking every 4-5MB
of loose objects accumulation may be a good rule of thumb.
<4> after repack, prune removes the duplicate loose objects.
-------------
Repack a small project into single pack.::
+
------------
$ git repack -a -d <1>
$ git prune
-
+------------
++
<1> pack all the objects reachable from the refs into one pack
and remove unneeded other packs
-------------
Individual Developer (Standalone)[[Individual Developer (Standalone)]]
$ git add . <1>
$ git commit -m 'import of frotz source tree.'
$ git tag v2.43 <2>
-
+------------
++
<1> add everything under the current directory.
<2> make a lightweight, unannotated tag.
-------------
Create a topic branch and develop.::
+
$ git pull . alsa-audio <10>
$ git log --since='3 days ago' <11>
$ git log v2.43.. curses/ <12>
-
+------------
++
<1> create a new topic branch.
<2> revert your botched changes in "curses/ux_audio_oss.c".
<3> you need to tell git if you added a new file; removal and
combined and include --max-count=10 (show 10 commits), --until='2005-12-10'.
<12> view only the changes that touch what's in curses/
directory, since v2.43 tag.
-------------
Individual Developer (Participant)[[Individual Developer (Participant)]]
$ git reset --hard ORIG_HEAD <6>
$ git prune <7>
$ git fetch --tags <8>
-
+------------
++
<1> repeat as needed.
<2> extract patches from your branch for e-mail submission.
<3> "pull" fetches from "origin" by default and merges into the
<7> garbage collect leftover objects from reverted pull.
<8> from time to time, obtain official tags from the "origin"
and store them under .git/refs/tags/.
-------------
Push into another repository.::
mothership$ cd frotz
mothership$ git checkout master
mothership$ git pull . satellite <5>
-
+------------
++
<1> mothership machine has a frotz repository under your home
directory; clone from it to start a repository on the satellite
machine.
mothership machine. You could use this as a back-up method.
<5> on mothership machine, merge the work done on the satellite
machine into the master branch.
-------------
Branch off of a specific tag.::
+
$ git checkout master
$ git format-patch -k -m --stdout v2.6.14..private2.6.14 |
git am -3 -k <2>
-
+------------
++
<1> create a private branch based on a well known (but somewhat behind)
tag.
<2> forward port all changes in private2.6.14 branch to master branch
without a formal "merging".
-------------
Integrator[[Integrator]]
$ git fetch ko && git show-branch master maint 'tags/ko-*' <11>
$ git push ko <12>
$ git push ko v0.99.9x <13>
-
+------------
++
<1> see what I was in the middle of doing, if any.
<2> see what topic branches I have and think about how ready
they are.
everything "ko-master" has.
<12> push out the bleeding edge.
<13> push the tag out, too.
-------------
Repository Administration[[Repository Administration]]
Examples
~~~~~~~~
-
Run git-daemon to serve /pub/scm from inetd.::
+
------------
david:x:1003:1003::/home/david:/usr/bin/git-shell
$ grep git /etc/shells <2>
/usr/bin/git-shell
-
+------------
++
<1> log-in shell is set to /usr/bin/git-shell, which does not
allow anything but "git push" and "git pull". The users should
get an ssh access to the machine.
<2> in many distributions /etc/shells needs to list what is used
as the login shell.
-------------
CVS-style shared repository.::
+
refs/heads/master alice\|cindy
refs/heads/doc-update bob
refs/tags/v[0-9]* david
-
+------------
++
<1> place the developers into the same git group.
<2> and make the shared repository writable by the group.
<3> use update-hook example by Carl from Documentation/howto/
<4> alice and cindy can push into master, only bob can push into doc-update.
david is the release manager and is the only person who can
create and push version tags.
-------------
HTTP server to support dumb protocol transfer.::
+
dev$ git update-server-info <1>
dev$ ftp user@isp.example.com <2>
ftp> cp -r .git /home/user/myproject.git
-
+------------
++
<1> make sure your info/refs and objects/info/packs are up-to-date
<2> upload to public HTTP server hosted by your ISP.
-------------
mistake, and gets it back from the index.
+
------------
-$ git checkout master <1>
-$ git checkout master~2 Makefile <2>
+$ git checkout master <1>
+$ git checkout master~2 Makefile <2>
$ rm -f hello.c
-$ git checkout hello.c <3>
-
+$ git checkout hello.c <3>
+------------
++
<1> switch branch
<2> take out a file out of other commit
-<3> or "git checkout -- hello.c", as in the next example.
-------------
+<3> restore hello.c from HEAD of current branch
+
-If you have an unfortunate branch that is named `hello.c`, the
-last step above would be confused as an instruction to switch to
-that branch. You should instead write:
+If you have an unfortunate branch that is named `hello.c`, this
+step would be confused as an instruction to switch to that branch.
+You should instead write:
+
------------
$ git checkout -- hello.c
Various ways to check your working tree::
+
------------
-$ git diff <1>
-$ git diff --cached <2>
-$ git diff HEAD <3>
-
+$ git diff <1>
+$ git diff --cached <2>
+$ git diff HEAD <3>
+------------
++
<1> changes in the working tree since your last git-update-index.
<2> changes between the index and your last commit; what you
would be committing if you run "git commit" without "-a" option.
<3> changes in the working tree since your last commit; what you
would be committing if you run "git commit -a"
-------------
Comparing with arbitrary commits::
+
------------
-$ git diff test <1>
-$ git diff HEAD -- ./test <2>
-$ git diff HEAD^ HEAD <3>
-
+$ git diff test <1>
+$ git diff HEAD -- ./test <2>
+$ git diff HEAD^ HEAD <3>
+------------
++
<1> instead of using the tip of the current branch, compare with the
tip of "test" branch.
<2> instead of comparing with the tip of "test" branch, compare with
the tip of the current branch, but limit the comparison to the
file "test".
<3> compare the version before the last commit and the last commit.
-------------
Limiting the diff output::
+
------------
-$ git diff --diff-filter=MRC <1>
-$ git diff --name-status -r <2>
-$ git diff arch/i386 include/asm-i386 <3>
-
+$ git diff --diff-filter=MRC <1>
+$ git diff --name-status -r <2>
+$ git diff arch/i386 include/asm-i386 <3>
+------------
++
<1> show only modification, rename and copy, but not addition
nor deletion.
<2> show only names and the nature of change, but not actual
you would only see the directory name if there is a change in a
file in a subdirectory.
<3> limit diff output to named subtrees.
-------------
Munging the diff output::
+
------------
-$ git diff --find-copies-harder -B -C <1>
-$ git diff -R <2>
-
+$ git diff --find-copies-harder -B -C <1>
+$ git diff -R <2>
+------------
++
<1> spend extra cycles to find renames, copies and complete
rewrites (very expensive).
<2> output diff in reverse.
-------------
Author
+
----------------
$ cd /path/to/my/codebase
-$ git-init-db <1>
-$ git-add . <2>
-
+$ git-init-db <1>
+$ git-add . <2>
+----------------
++
<1> prepare /path/to/my/codebase/.git directory
<2> add all existing file to the index
-----------------
Author
+
------------
$ git commit ...
-$ git reset --soft HEAD^ <1>
-$ edit <2>
-$ git commit -a -c ORIG_HEAD <3>
-
+$ git reset --soft HEAD^ <1>
+$ edit <2>
+$ git commit -a -c ORIG_HEAD <3>
+------------
++
<1> This is most often done when you remembered what you
just committed is incomplete, or you misspelled your commit
message, or both. Leaves working tree as it was before "reset".
<3> "reset" copies the old head to .git/ORIG_HEAD; redo the
commit by starting with its log message. If you do not need to
edit the message further, you can give -C option instead.
-------------
Undo commits permanently::
+
------------
$ git commit ...
-$ git reset --hard HEAD~3 <1>
-
+$ git reset --hard HEAD~3 <1>
+------------
++
<1> The last three commits (HEAD, HEAD^, and HEAD~2) were bad
and you do not want to ever see them again. Do *not* do this if
you have already given these commits to somebody else.
-------------
Undo a commit, making it a topic branch::
+
------------
-$ git branch topic/wip <1>
-$ git reset --hard HEAD~3 <2>
-$ git checkout topic/wip <3>
-
+$ git branch topic/wip <1>
+$ git reset --hard HEAD~3 <2>
+$ git checkout topic/wip <3>
+------------
++
<1> You have made some commits, but realize they were premature
to be in the "master" branch. You want to continue polishing
them in a topic branch, so create "topic/wip" branch off of the
current HEAD.
<2> Rewind the master branch to get rid of those three commits.
<3> Switch to "topic/wip" branch and keep working.
-------------
Undo update-index::
+
------------
-$ edit <1>
+$ edit <1>
$ git-update-index frotz.c filfre.c
-$ mailx <2>
-$ git reset <3>
-$ git pull git://info.example.com/ nitfol <4>
-
+$ mailx <2>
+$ git reset <3>
+$ git pull git://info.example.com/ nitfol <4>
+------------
++
<1> you are happily working on something, and find the changes
in these files are in good order. You do not want to see them
when you run "git diff", because you plan to work on other files
remain there.
<4> then you can pull and merge, leaving frotz.c and filfre.c
changes still in the working tree.
-------------
Undo a merge or pull::
+
------------
-$ git pull <1>
+$ git pull <1>
Trying really trivial in-index merge...
fatal: Merge requires file-level merging
Nope.
Auto-merging nitfol
CONFLICT (content): Merge conflict in nitfol
Automatic merge failed/prevented; fix up by hand
-$ git reset --hard <2>
-
+$ git reset --hard <2>
+$ git pull . topic/branch <3>
+Updating from 41223... to 13134...
+Fast forward
+$ git reset --hard ORIG_HEAD <4>
+------------
++
<1> try to update from the upstream resulted in a lot of
conflicts; you were not ready to spend a lot of time merging
right now, so you decide to do that later.
<2> "pull" has not made merge commit, so "git reset --hard"
which is a synonym for "git reset --hard HEAD" clears the mess
from the index file and the working tree.
-
-$ git pull . topic/branch <3>
-Updating from 41223... to 13134...
-Fast forward
-$ git reset --hard ORIG_HEAD <4>
-
<3> merge a topic branch into the current branch, which resulted
in a fast forward.
<4> but you decided that the topic branch is not ready for public
tip of the current branch in ORIG_HEAD, so resetting hard to it
brings your index file and the working tree back to that state,
and resets the tip of the branch to that commit.
-------------
Interrupted workflow::
+
------------
$ git checkout feature ;# you were working in "feature" branch and
$ work work work ;# got interrupted
-$ git commit -a -m 'snapshot WIP' <1>
+$ git commit -a -m 'snapshot WIP' <1>
$ git checkout master
$ fix fix fix
$ git commit ;# commit with real log
$ git checkout feature
-$ git reset --soft HEAD^ ;# go back to WIP state <2>
-$ git reset <3>
-
+$ git reset --soft HEAD^ ;# go back to WIP state <2>
+$ git reset <3>
+------------
++
<1> This commit will get blown away so a throw-away log message is OK.
<2> This removes the 'WIP' commit from the commit history, and sets
your working tree to the state just before you made that snapshot.
-<3> After <2>, the index file still has all the WIP changes you
- committed in <1>. This sets it to the last commit you were
- basing the WIP changes on.
-------------
+<3> At this point the index file still has all the WIP changes you
+ committed as 'snapshot WIP'. This updates the index to show your
+ WIP files as uncommitted.
Author
------
$ git-checkout-index -n -f -a && git-update-index --ignore-missing --refresh
----------------
-On an inefficient filesystem with `core.ignorestat` set:
-
+On an inefficient filesystem with `core.ignorestat` set::
++
------------
-$ git update-index --really-refresh <1>
-$ git update-index --no-assume-unchanged foo.c <2>
-$ git diff --name-only <3>
+$ git update-index --really-refresh <1>
+$ git update-index --no-assume-unchanged foo.c <2>
+$ git diff --name-only <3>
$ edit foo.c
-$ git diff --name-only <4>
+$ git diff --name-only <4>
M foo.c
-$ git update-index foo.c <5>
-$ git diff --name-only <6>
+$ git update-index foo.c <5>
+$ git diff --name-only <6>
$ edit foo.c
-$ git diff --name-only <7>
-$ git update-index --no-assume-unchanged foo.c <8>
-$ git diff --name-only <9>
+$ git diff --name-only <7>
+$ git update-index --no-assume-unchanged foo.c <8>
+$ git diff --name-only <9>
M foo.c
-
-<1> forces lstat(2) to set "assume unchanged" bits for paths
- that match index.
+------------
++
+<1> forces lstat(2) to set "assume unchanged" bits for paths that match index.
<2> mark the path to be edited.
<3> this does lstat(2) and finds index matches the path.
-<4> this does lstat(2) and finds index does not match the path.
+<4> this does lstat(2) and finds index does *not* match the path.
<5> registering the new version to index sets "assume unchanged" bit.
<6> and it is assumed unchanged.
<7> even after you edit it.
<8> you can tell about the change after the fact.
<9> now it checks with lstat(2) and finds it has been changed.
-------------
Configuration