Git

From YobiWiki
Jump to navigation Jump to search

Links

Install

sudo apt-get install git-svn git-doc git-gui tig

Writing to global ~/.gitconfig file:

git config --global user.name "Your Name Comes Here"
git config --global user.email you@yourdomain.example.com
git config --global color.diff auto
git config --global color.status auto
git config --global color.branch auto

Creating a .git in the current (project) directory:

git init

Working on a project

Initial project

Add manually files/directories e.g. with

git init
git add .
git commit

Copying existing project

Clone an existing Git repository into a to-be-created target directory:

git clone /path/to/other/repository target

Remote repositories can also be accessed with paths like

ssh://login@host/path/to/repository
git://git.software.org/trunk
http://git.software.org/trunk

Later to update the local repository according to the remote repository:

git pull

Symmetrically the remote repository owner could also get the changes we've done locally if she does:

git pull /path/to/our/target

Or we could send them ourselves if we've write access on the remote:

git push

BTW the remote can create a shortcut to us to not have to provide our full path everytime

git remote add ourshortcut /path/to/our/target

And now use directly

git remote show ourshortcut
git pull ourshortcut

Note that git pull ourshortcut ==

git fetch ourshortcut
git merge ourshortcut/master

Using a Subversion server

Using git-svn:

Getting the full project:

# git clone =>
git-svn --username=xxxxx clone http://subversion.server.com/project -T trunk -b branches -t tags
(git-gc to compress if it took a big room)

Updating the local repository according to the subversion server:

# git pull =>
git-svn rebase

Some tips from here:

  • While doing a rebase, if anything bad happens, you end up on a "(no-branch)" branch.
  • When doing a "git status", you'll see a ".dotest" file in your working directory. Just ignore it.
  • If you want to bail, do a "git rebase --abort". (Note there is no "git svn rebase --abort".)
  • Fix the merge conflict file manually, then do a "git add [file]".
  • Next do a "git rebase --continue". (Note there's no "svn" version of this either.)
  • If it complains about "did you forget to call 'git add'?", then evidently your edit turned the conflict into a no-op change. Do a "git rebase --skip" to skip it. (Very weird, but true.)
  • Rinse and repeat until the lather is gone, your scalp silky smooth, and the rebase is complete. At any time you can "git rebase --abort" to bail.

Sending the local changes to the subversion server:

# git push =>
git-svn dcommit


By error I did

git commit --amend

on a synchronized git repository, so I lost remotes/trunk in the gitk view but the remote branch is still visible with git branch -r, strange...

$ git-svn rebase
First, rewinding head to replay your work on top of it...
Nothing to do.

solved the problem

SVN relocation:
git-svn doesn't support relocation of the SVN server and doing it by hand is very difficult so if possible push all your local changes before relocation then make a new clone from the new location.

One day you'll be bored of SVN and want to get rid of it completely :-)

Create a new git repository remotely somewhere else (see above), which will become the origin we didn't have.

git remote add origin ssh://myuser@repo.or.cz/srv/git/myproject.git
git pull origin master
git push

Now it's better to make sure git-svn cannot interfere with it anymore:
Fetch the project in a new place

git clone ssh://myuser@repo.or.cz/srv/git/myproject.git
git pull

And drop your old git-svn working directory

Using repo.or.cz

http://repo.or.cz/ can be used to make a publicly available git repo.

  1. Create a new user: http://repo.or.cz/m/reguser.cgi
    When creating a user you need a public ssh key to authenticate yourself.
  2. Create a new repo: http://repo.or.cz/m/regproj.cgi
    • two different modes are available for a new repo:
      • mirror mode: the new repo will mirror an existing repo by checking it every hour for changes
      • push mode: users you give permission to can push to the repo
    • all the info asked when you register your repo can be changed afterwards on the project admin page
  3. Add yourself and other users you want to give "push" access via the admin page
  4. Git repo is accessible via

Basic usage

Edition

Schedule a file for committing

git add <file>

Committing

git commit

Note that a modified file must be explicitly added every time, unless you use

git commit -a

Or

git commit <file>

File renaming is implicit, so you don't have to take care, just rename your files if you want (really??), but there is also the explicit commands

git mv <file>
git rm <file>

Diff/patch

Diff between working files & to-be-committed index

git diff

Diff between to-be-committed index & repository

git diff --cached

Diff between working files & repository

git diff HEAD

With specific revision or path

git diff <rev> <path>

E.g with one but last commit

git diff HEAD~1

This provides usage patches, including metadata, can be applied with

git apply

Status & revert

Status of local working files

git status

To restore (revert) a file from the last revision

git checkout <path>

Revert all changes (!)

git checkout -f

You can amend your latest commit (re-edit the metadata as well as update the tree) using this (it is only safe to amend the commit messages that have not been seen by anyone else, aka, you've not pushed, nobody else has pulled from you).

git commit --amend

Or toss your latest commit away completely using

git reset HEAD^

This will not change the working tree.

To unstage a change to-be-committed (e.g. git add *)

git reset HEAD <file>

History

git log

With nice stats:

git log --stat --summary

See from which revision came the lines of a file

git blame <file>

Or search for commits affecting a specific line

git log -S"string"

You can see the contents of a file

git show rev:path/to/file

The listing of a directory

git show rev:path/to/directory

Or a commit with:

git show rev

Tags & branches

Create a tag:

git tag -a <name>

List tags and show the tag message:

git tag -l
git show <tag>

Create a branch:

git branch <branch> [<rev>]

Switch to the branch

git checkout <branch>

List branches (current is flagged by a *)

git branch

To move your tree to some older revision, use:

git checkout <rev>
git checkout <prevbranch>

Default branch is "master"

Merge

Assuming you are in the trunk and want to merge a given branch here:

git merge branch

If the merge went nice automatically, a commit is done automatically too, to avoid it:

git merge --no-commit branch

Aside from merging, sometimes you want to just pick one commit from a different branch. To apply the changes in revision rev and commit them to the current branch use:

git cherry-pick rev

Rebase

Not yet clear what's the diff with merge...

  • Find all your (committed) changes, since you branched
  • Reset your branch, so that it's an exact copy of the current master
  • Re-apply all your changes again
git checkout branch_name
git rebase master

If conflicts occur, and sooner or later they will,

# manually edit the conflicting files
git add file(s)
git rebase --continue

See also "git-mergetool"


Rework commit history

You want:

  • Two different commits to be combined into a single commit
  • Remove a commit entirely from the history
  • Change the commit message
  • Change the order that commits appear in the history
  • Split one big commit into multiple smaller commits
git rebase --interactive COMMIT_ID

COMMIT_ID should be the one BEFORE you want to fiddle with.

To learn about splitting a single commit up into multiple commits:

man git-rebase
# see "SPLITTING COMMITS" section

Ignoring some files

cat > .gitignore <<EOF
*.pyc
*~
EOF
git add .gitignore

Now you can also delete all files neither tracked nor ignored with:

git clean

Server

First making a bare repository

From http://book.git-scm.com/4_setting_up_a_public_repository.html
Assume your personal repository is in the directory ~/proj. We first create a new clone of the repository and tell git-daemon that it is meant to be public:

$ git clone --bare ~/proj proj.git
$ touch proj.git/git-daemon-export-ok

The resulting directory proj.git contains a "bare" git repository--it is just the contents of the ".git" directory, without any files checked out around it.
Next, copy proj.git to the server where you plan to host the public repository. You can use scp, rsync, or whatever is most convenient.
People with ssh login can then clone it with e.g.:

$ git clone git.server:/home/git/proj.git

Later you'll probably want to update that repository, still via ssh:

$ git remote add myserver git.server:/home/git/proj.git

Then for pushing changes:

$ git push myserver

Multiple developers access

See doc provided by

# apt-get install git-doc

See especially last part of /usr/share/doc/git-doc/everyday.txt|.html

CVS-style shared repository:

# addgroup git
# adduser <toto> git
# chgrp -R git proj.git
# find proj.git -type d -exec chmod g+s {} \;
# chmod g+w -R ssh-tunnel.git
  • You can provide people limited ssh accounts with restricted git-shell
  • Apparently it's also possible to get RW access via http (via webdav), cf /usr/share/doc/git-doc/howto/setup-git-server-over-http.txt
  • For more fine control, see /usr/share/doc/git-doc/howto/update-hook-example.txt

Exporting the git repository via the git protocol

This is the preferred method.
Under Debian you need the git-daemon-run server.

apt-get install git-daemon-run

The daemon will listen on port 9418. By default, it will allow access to any directory that looks like a git directory and contains the magic file git-daemon-export-ok. Passing some directory paths as git-daemon arguments will further restrict the exports to those paths.
Then you can read /usr/share/doc/git-daemon-run/README.Debian
It expects repositories to be under var/cache/git , symlinks are ok, e.g.

ln -s ~/git/foo/.git /var/cache/git/foo.git
Note that in a vserver some difficulties are appearing: git-daemon-run requires runit which counts on the init process (otherwise install fails). To have a real init process in the vserver, the vserver should be created with --initstyle=plain (see #306390
As it was too late I looked into the build script and it looks like it doesn't do more than creating a file /etc/vservers/xxxx/apps/init/style containing the world "plain".
Then another consequence is that the ssh daemon was not running anymore, apparently initstyle=plain makes impossible to chroot from a vserver. You can run ssh without privilege separation (/etc/ssh/sshd_config -> UsePrivilegeSeparation no)


People can then clone it with

git clone git://git.server/git/proj.git

Exporting the git repository via http

The git protocol gives better performance and reliability, but on a host with a web server set up, http exports may be simpler to set up.
All you need to do is place the newly created bare git repository in a directory that is exported by the web server, and make some adjustments to give web clients some extra information they need:

cd proj.git
git --bare update-server-info
chmod a+x hooks/post-update


People can then clone it with

git clone http://git.server/git/proj.git

Web frontent for git repository: gitweb

apt-get install gitweb
less /usr/share/doc/gitweb/README.Debian
less /usr/share/doc/git-core/README.Debian

You can settle a vserver as proposed in th edoc but note that the example is wrong, css & jpg are in /usr/share/gitweb/ not in /var/www
gitweb expects also projects to be in /var/cache/git (configurable in /etc/gitweb.conf)
Add a description of your project in .git/description it will be visible in gitweb.

Changing owner: edit proj.git/config

[gitweb]
   owner = "Toto le Héros"

New project creation

Here is a little script to automate empty shared repository creation:

phil@devel:/var/cache/git$ cat create-proj.sh 
#!/bin/bash

if [ "$1" == "" ] ; then
    echo "Please give me a project name [a-z]+"
    exit 1
fi

projname=$1

mkdir $projname.git
cd $projname.git/

git init --bare
mcedit description
echo -e "[gitweb]\n\towner = \"fill me\"" >> config
mcedit config
touch git-daemon-export-ok
git --bare update-server-info
chmod a+x hooks/post-update
sudo chgrp -R git .
sudo find . -type d -exec chmod g+s {} \;
sudo chmod g+w -R .

Misc

  • Revisions are SHA-1 hashes, not incremental numbers.
    You can refer to the latest revision by HEAD, its parent as HEAD^ and its parent as HEAD^^ = HEAD~2
    You can also just type the first digits of the hash (if it's enough to get a unique ID)
    man git-rev-parse for more details
  • The Git commands are in the form git command. You can interchangeably use the git-command form as well.
  • Setting up a public repository where you'll push your stuff
    • git --bare init --shared ??
  • Though not required, it's a good idea to begin the commit message with a single short (less than 50 character) line summarizing the change, followed by a blank line and then a more thorough description.
  • Git on VFAT fs: mount it with option shortname=mixed otherwise git doesn't recognize the repository

etckeeper

Description: store /etc in git, mercurial, or bzr
The etckeeper program is a tool to let /etc be stored in a git, mercurial, or bzr repository. It hooks into APT to automatically commit changes made to /etc during package upgrades. It tracks file metadata that version control systems do not normally support, but that is important for /etc, such as the permissions of /etc/shadow.
It's quite modular and configurable, while also being simple to use if you understand the basics of working with version control.

apt-get install etckeeper

Read this!!!

zless /usr/share/doc/etckeeper/README.gz

Crash course:

etckeeper init
cd /etc
git commit -m "initial checkin"
git gc

For the rest, read /usr/share/doc/etckeeper/README.gz