Wednesday 21 August 2013

Version control - Git

[Setup git in Windows]

1, download client (GUI client and binary realese) from official website: http://git-scm.com/;
  for windows, it's msysgit.
  You can also download it from official site for msysgit: http://msysgit.github.io/ (moved from google to github), detail downloads : https://code.google.com/p/msysgit/downloads/list?q=full+installer+official+git

2, install it.(remember to choose second option for PATH env in order to use context sensitive menu.

3, config the user info and client look and feel.
$git config --global user.name "xxx"
$git config --global user.email "yy@zz.com"
$git config --global color.ui true

4, create local directory and clone the project
assume your local dir is C:\dev\proj
$cd /c/dev/proj
$git clone user@host : project URL

5, now you can add/update/delete source code; or add/udpate/delete branch;

Git Basics:
+ distributed VCS; 
+ everything is local including commit; you can work offline with no network connection;
+ push and pull(fetch & merge) for sync among different hosts. whenever you have network connection;
+ snapshots vs deltas
+ three states:
   + working directory(work tree); modified
   + stage area(index); staged
   + git directory(repo); committed
Committed means that the data is safely stored in your local database. 
Modified means that you have changed the file but have not committed it to your database yet. Staged means that you have marked a modified file in its current version to go into your next commit snapshot.

The Git directory is where Git stores the metadata and object database for your project. This is the most important part of Git, and it is what is copied when you clone a repository from another computer.
The working directory is a single checkout of one version of the project. These files are pulled out of the compressed database in the Git directory and placed on disk for you to use or modify.
The staging area is a simple file, generally contained in your Git directory, that stores information about what will go into your next commit. It’s sometimes referred to as the index, but it’s becoming standard to refer to it as the staging area.

+ configuration has three levels:
/etc/gitconfig file: Contains values for every user on the system and all their repositories. If you pass the option--system to git config, it reads and writes from this file specifically.
~/.gitconfig file: Specific to your user. You can make Git read and write to this file specifically by passing the --global option.
config file in the git directory (that is, .git/config) of whatever repository you’re currently using: Specific to that single repository. Each level overrides values in the previous level, so values in .git/config trump those in /etc/gitconfig.

+ configure
1, user identity
$ git config --global user.name "XXX"

$ git config --global user.email "YY@ZZ.com"
2, editor
$ git config --global core.editor emacs
3, diff tool
$ git config --global merge.tool vimdiff
4, show configurations
git config --list

+ remote & local
   + git remote; or git remote -v to show where you clone is from.

[Conventions]
+ use bare repo if you want to set up a git server (conceptually there is no central server, through this we just want to keep one host as a primary host);
- server repo is bare mode; no working directory. you can't use it directly for dev;
- master branch is used only for formal release; don't checkout master branch for coding;
- dev branch is a collaborative branch;

[Tips]
- you can create new branch in server side(with bare repo), but you can not check it out as there is no working tree/directory there;

- when you do a fetch that brings down new remote branches, you don’t automatically have local, editable copies of them. In other words, you don’t have a new local serverbranch — you only have an origin/serverbranch pointer that you can’t modify.
To merge this work into your current working branch, you can run git merge origin/serverbranch. If you want your own serverbranch branch that you can work
on, you can base it off your remote branch: "git checkout -b serverbranch origin/serverbranch" (looks like, use "git checkout origin/serverbranch" also works, it will automatically created a local branch with same name)

- "git checkout <branch>" : If <branch> is not found but there does exist a tracking branch in exactly one remote (call it <remote>) with a matching name, treat as equivalent to "git checkout -b <branch> --track <remote>/<branch>"

"git checkout fix" is identical as "git checkout --track origin/fix", and identical as "git checkout -b fix origin/fix"; if there is no local branch with same name already. it will automatically create the new local branch.


- to push a local branch to server, you can use "git push origin localbranch" this can push the localbranch to server. another form is "git push origin localbranch:localbranch" with same name, or with a new branch name on server side "git push origin localbranch:newnamebranch"

- push a local branch to origin/server, it will not take the remote branch(you just pushed) as the upstream of the local branch automatically. use "git branch --verbose --verbose -a" to show upstream relationship.


- use "git fetch -p"(prune) if there is some remote branch already removed/deleted, but you can not get it removed in your local host through fetch.
- to remove a remote branch, use "git push origin :featA" = "git push [alias] [null]:[branch name]".  try to remember this as "git push [remotename] [localbranch]:[remotebranch]" syntax.

- use "git reset HEAD <file>" to unstage a file
- use "git checkout -- <file>..." to discard changes in working directory
- to merge from remote branch or other local branch, you need make sure there is no modified file in working tree.
- "git reset --hard <commit>/HEAD", will reset the index and working tree. Any changes to tracked files in the working tree since <commit> are discarded.
- "git reset --soft <commit>/HEAD", Does not touch the index file nor the working tree at all (but only resets the head to <commit>, just like all modes do). This leaves all your changed files "Changes to be committed", as git status would put it.

- "git reset HEAD <file>" default is mixed mode, it will reset the index but not the working tree (i.e., the changed files are preserved but not marked for commit) and reports what has not been updated. This is the default action.





- after fix the conflicts via editor, you need run "git add" to mark it as resolved (staging the file mark it as resolved in Git) so that git knows the conflict is resolved. if you use mergetool, after you exit the tool git will ask you if the merge is successful, if yes, it will stage the file and mark it as resolved.
- for newly added file, you can not use "git commit -am 'blabla' ", you need first add it then commit;

- rebase is a little bit confusing in git. but it's useful to make history linear; when you rebase from another branch, git will find the common commit between two branches and reapply every commit you have that is not in the other branch. Each time when git reapply a commit, you may need to resolve the conflict, for any conflict resolved, you need use "git add" to tell git the conflict is resolved. and then "git rebase --continue"

- set "HOME" env in windows(HOME=c:\users\uid\) to let msysgit to store the .gticonfig and other config files under this folder; if you set the HOME env as C:\, then the ".gitconfig" will be stored in "C:\users\<uid>\AppData\Local\VirtualStore" this is because git is not permitted to store files at C:\, so it use the virtualStore.
- right click the shortcut of gitbash/gitgui to set the dir to start with ("start in" box);

- two ways to create a bare repo:
A: create a repo from existing project, and then clone a bare repo;
B: git init --bare directly with a empty bare repo, and then clone it from another host and push contents;






[git server setup]
1, suppose you have a local repository setup with "git init" under dir "/opt/projects/my_project". there will be a ".git" dir under /opt/projects/my_project". go to that directory and execute the following command": git clone --bare <repo> <dir>
$ cd /opt/projects
$ mkdir my_project
$ add some source dir/files
$ git init    #this will create a repo for my_project (a ".git" created under /opt/projects/my_project dir)
$ cd /opt/projects
$ git clone --bare my_project my_project.git
Initialized empty Git repository in /opt/projects/my_project.git/
after this, there will be a bare repo in /opt/projects/my_project.git
This is roughly equivalent to something like
$ cp -Rf my_project/.git my_project.git

2, putting the bare repo  on a server
scp: secure file transfer over network; -r means recursively; git.exmple.com is the server to put; /opt/git is the dir to put;
$ scp -r my_project.git user@git.example.com:/opt/git

3, at this point, anyone else can clone the repo via:(need input password of user named "user" )
$ git clone user@git.example.com:/opt/git/my_project.git

4, for every developer that need to access the server(via ssh), you need 
either create a user id in the server for each of them;
or create a single ‘git’ user on the machine, ask every user who is to have write access to send you an SSH public key, and add that key to the ~/.ssh/authorized_keys file of your new ‘git’ user. At that point, everyone will be able to access that machine via the ‘git’ user. This doesn’t
affect the commit data in any way — the SSH user you connect as doesn’t affect the commits you’ve recorded.

5, gen SSH pub key and send to git server
$ ssh-keygen  (run under ".ssh" dir under home dir C:\users\<uid>\.ssh)
leave passphrase as empty to avoid inputing password every time you interact with git server;
$ scp id-rsa.pub user@server:/path

6, add every developer's public key to the authorized_keyfile for git user. (under /home/git/.ssh)
$ cat /tmp/id_rsa.john.pub >> ~/.ssh/authorized_keys
$ cat /tmp/id_rsa.josie.pub >> ~/.ssh/authorized_keys
$ cat /tmp/id_rsa.jessica.pub >> ~/.ssh/authorized_keys

[tips part 2]
- if you use gitbash(wiondows host) to clone a github repo, and get the following error:
$ git clone https://github.com/msysgit/msysgit.git syslab
Cloning into 'syslab'...
fatal: unable to access 'https://github.com/msysgit/msysgit.git/': Failed connect to github.com:443; No error
this means you need config a proxy for it. 
you can use 
$git config --global http.proxy <proxy server>:<port>
BTW, if you use 
$sudo -u git -H clone https://github.com/msysgit/msysgit.git syslab
then you need first switch to user git to config the http proxy(via git config --global http.proxy)

No comments:

Post a Comment