Git
From KevinWiki
Contents
|
Git
Client-side Installation
In the client,
$ apt-get install git-core
Or to install the latest version of Git on Ubuntu
add-apt-repository ppa:git-core/ppa apt-get update apt-get install git-core
Configuration
User Info
$ git config --global user.name "GivenName Surname" $ git config --global user.email user@email.address
Default Text Editor
$ git config --global core.editor "sublime-text -w"
External Diff Tool
Meld As External Diff Tool
- To use Meld as a diff tool, install Meld
$ sudo apt-get install meld
- Set it as the default diff tool
$ git config --global diff.external meld
- It doesn't work and gives the following error messages.
$ git diff Usage: meld Start with an empty window meld <file|dir> Start a version control comparison meld <file> <file> [<file>] Start a 2- or 3-way file comparison meld <dir> <dir> [<dir>] Start a 2- or 3-way directory comparison meld <file> <dir> Start a comparison between file and dir/file meld: error: too many arguments (wanted 0-4, got 7)
- Create ~/diff.py
#!/usr/bin/python import sys import os os.system('meld "%s" "%s"' % (sys.argv[2], sys.argv[5]))
- Make it executable
$ chmod a+x ~/diff.py
- Set the script as the diff tool
$ git config --global diff.external ~/diff.py
- Now it works
$ git diff $ git diff HEAD
Meld as Diff Tool
- This way is much easier.
$ git config --global diff.tool meld
$ git difftool
Meld as Diff Tool
$ git config --global diff.tool vimdiff
Unset External Diff Tool
$ git config --global --unset diff.external
Commit Template
Create a template file
e.g.) $HOME/git/.your-config/git-commit-comment-template.txt
CLOSED - #TICKET_NUMBER: Summary TICKET_URI Details
$ git config --global commit.template $HOME/git/.your-config/git-commit-comment-template.txt
Etc.
$ git config --global color.ui true
Server-side Installation
In the server,
$ apt-get install git
Gitolite
Add User to Manage Gitolite
- Add user to manage gitolite
$ adduser \ --system \ --shell /bin/bash \ --gecos 'git version control' \ --group \ --disabled-password \ --home /home/git \ git Adding system user `git' (UID 108) ... Adding new group `git' (GID 110) ... Adding new user `git' (UID 108) with group `git' ... Creating home directory `/home/git' ...
Create SSH key
$ ssh-keygen -t rsa
/home/username/.ssh/some_git_rsa [ENTER] [ENTER]
Transfer SSH Keys to Server
$ ssh-copy-id '-p PORT_NUMBER -i /home/user/.ssh/some_git_rsa.pub git_user@host'
If it doesn't work because the user is the only user who can access the server with his/her ssh key so accessing with git_user doesn't work.
$ scp -P PORT ~/.ssh/some_git_rsa.pub user@host:
Log in with the user account
$ ssh -p PORT user@host $ mv some_git_rsa.pub git.pub
Setup
$ su - git $ cd ~ $ echo "PATH=$HOME/bin:$PATH" >> ~/.bashrc
- don't need these 2 lines
$ mkdir .ssh $ cat /home/user/git.pub >> /home/git/.ssh/authorized_keys
$ exit
Gitolite Installation
$ sudo -i $ apt-get install gitolite [ENTER] -> :q to exit $ exit
Setup git User
$ su - git $ gl-setup /home/user/git.pub
$ vim /etc/ssh/sshd_config
Add git to the allowed user
AllowUsers user git
Restart ssh
$ service ssh restart
Test
- Testing (from user local machine)
$ ssh -p PORT_NUMBER git@host
Having many keys?
$ ssh -p PORT_NUMBER -i ~/.ssh/user@host1.pub git@host
For debugging
$ ssh -p PORT_NUMBER -vT git@host
$ mkdir some-dir $ cd some-dir $ git clone git@host:gitolite-admin
Or if you use a specific port,
$ git clone ssh://git@host:PORT_NUMBER/gitolite-admin
Add Git User (through Gitolite)
Adding User
$ cd gitolite-admin/keydir $ mkdir user_name $ cp -p ~/.ssh/user@host1.pub . $ cp -p ~/.ssh/user@host2.pub . $ git add user@host1.pub $ git commit -a -m "users added: user@host1 and user@host2" $ git push
If directly copied to /home/git/.gitolite/keydir
, run
$ gl-setup
to apply the changes
Usage
Initializing a Repository in an Existing Directory
- To make a directory a git repository, go to the project directory and run the following command
$ git init
Then it will create a new directory named .git
inside the project directory. The .git
folder contains all necessary files for the git repository.
Host Info Config using SSH_Config
Create ~/.ssh/config
file and edit.
Host host.name Hostname host.name Port 1111 Host another.host.name Hostname another.host.name Port 2222 Host host1 Hostname host.name Port 1111 User git IdentityFile ~/.ssh/git_rsa Host user-host2 Hostname host2.name Port 1234 User user IdentityFile ~/.ssh/user@localhost1 Host user-host3 Hostname host3.com Port 1122 User user IdentityFile ~/.ssh/user@localhost1
IdentityFile is a private key
To use this info,
$ git clone git@host1:repo-name # it will use 'git' as a user and access the server 'host.name' using the port nubmer 1111.
$ git clone git@host1:repo-name # it will use 'user' as a user and access the server 'host2.name' using the port nubmer 1234.
Push to Specific Host
$ git push git@host1:repo-name master
Set up Project Specific User Info
- Move to the project repository
$ git config user.email user@email.address
To see and edit all the config details
$ git config -e
.gitignore
To exclude files when committing, create .gitignore file and put in the project root (git project repo root). For maven project, the content should be
target/
To set up the global ignore file
$ git config --global core.excludesfile $HOME/git/.your-config/.global-gitignore
Other gitignore files,
https://github.com/github/gitignore
.gitignore for Eclipse and Maven (for Kevin)
target/ *.pydevproject .project .classpath .settings/ .metadata bin/ tmp/ *.tmp *.bak *.swp *~.nib local.properties .loadpath # External tool builders .externalToolBuilders/ # Locally stored "Eclipse launch configurations" *.launch # CDT-specific .cproject # PDT-specific .buildpath
Commit
- Add a file
$ git add fileName
- Commit changes
$ git commit -m "comment"
- Add all the files and folders
$ git add -A # It is equivalent to git add .; git add -u # git add . -> add all changed and new ones but not removed ones # git add -u -> changed and removed but not new ones.
Amend Last Comment
- Amend the last comment
$ git commit --amend -m "New comment"
Push
Add Remote
- To view all remote
$ git remote -v
- Add a remote
$ git remote add origin git@git-repo:project
Then
$ git push -u origin master
Or
$ git config branch.master.remote origin $ git config branch.master.merge refs/heads/master
Push to Remote
- Push to the remote git repository
$ git push
- If it gives error messages like:
No refs in common and none specified; doing nothing. Perhaps you should specify a branch such as 'master'.
(It doesn't happen if you have already done git push -u origin master
).
- Do
$ git push origin master
Revert
Reset
- Revert to last commit.
$ git reset --hard HEAD
Or to specific commit/tag/branch
$ git reset --hard <tag/branch/commit id>
- Check the id using git log
$ git log
- To push it
$ git push <reponame> -f
Check out
- Or change the name of master branch then check out from the commit to be used and make it master
- Rename the current master branch
-
$ git branch -m another_name_for_master
-
- Check out from another commit:
-
$ git checkout a1b2c3a3blah
-
- Make it the new master branch:
-
$ git checkout -b master
-
- If the old master is no longer needed and has to be removed, remove it by
$ git branch -D another_name_for_master
Restore Removed File
This has to be tested first then should be rewritten.
Find the last commit that affected the given path. As the file isn't in the HEAD commit, this commit must have deleted it.
$ git rev-list -n 1 HEAD -- <file_path>
Then checkout the version at the commit before.
$ git checkout <deleting_commit>^ -- <file_path>
Or in one command, if $file is the file.
$ git checkout $(git rev-list -n 1 HEAD -- "$file")^ -- "$file"
- Reference
Branch
Create Branch
- Create branch
$ git branch branch_name
- Change to the branch just created
$ git checkout branch_name
OR
- Create and change
git checkout -b branch_name
- Back to master
$ git checkout master
- To push,
$ git push origin branch_name
Change Branch
- Change branch
$ git checkout branch_name
- It does not work when the local git repo has multiple remote repositories. If it's the case,
$ git checkout -b branch remote/branch
e.g.)
$ git checkout -b my-branch origin/my-branch
Pull Without Checkout
- To pull a specific branch without checking out
$ git fetch <remote> <remoteBranch>:<localBranch>
e.g.)
git fetch origin master:master
git fetch origin adding-new-feature:adding-new-feature
Tag
List Tags
$ git tag
View Tag
- To view tag data with commit details.
$ git show tag_name
Create Tag
- Create Tag
$ git tag -a tag_name -m 'tag message: new version blah blah'
- Tag later
$ git tag -a tag_name -m 'tag message' commit_checksum
e.g.)
$ git tag -a v1.5 -m 'new version with blah blah' b015e9d
- To see the list of checksum use the following command.
$ git log --pretty=oneline
Remove Tag
$ git tag -d tag_name
Merge Multiple Git Repositories into One
If the directory structures look like this
parent-dir (not git repo) │ ├─git-repo1 ## each is connected to its own remote git repository │ ├─src │ └.git │ ├─git-repo2 ## each is connected to its own remote git repository │ ├─src │ └.git │ └─ git-repo3 ## each is connected to its own remote git repository ├─src └.git
To make it like
parent-dir (now it is git repo) ├─src ## contains all the files and sub-dirs from those three repositories (git-repo1, git-repo2 and git-repo3). └.git
and it still keeps all the histories from all those repositories, do following instructions.
- Initialize the new repository directory.
$ cd parent-dir $ git init
- Pull the old ones and remove these one by one.
$ git pull git-repo1 ## If there is any conflict, solve it first then ## commit the changes $ git add file $ git commit -a ## Now pull the one had conflict issue again. $ git pull git-repo1 $ rm -rf git-repo1 $ git pull git-repo2 $ rm -rf git-repo2 $ git pull git-repo3 $ rm -rf git-repo3
- Done! Add the remote repo info if necessary.
Migration from SVN to Git
Install git-svn
$ apt-get install git-svn
Prepare for Migration
In some dir, create users.txt having all the user info e.g.)
USERNAME = FirstName LastName <user@host>
Migrate
Without Tags
$ git svn clone --stdlayout --no-metadata -A users.txt --username=USERNAME https://svn.repo/some-parent-folder/project-folder project-tmp
(https://svn.repo/some-parent-folder/project-folder <- Not trunk)
$ cd project-tmp
$ git svn fetch
- To view the other SVN branches
$ git branch -r
$ cd ..
$ git clone project-tmp project $ rm -Rf project-tmp
$ cd project $ git remote rm origin
- Before this, add git repo for the project first.
$ git remote add origin git@git-repo:project
- To view all remote
$ git remote -v
$ git config branch.master.remote origin $ git config branch.master.merge refs/heads/master
- add user info to project/.git/config
[user] email = user@host
$ git push -u origin master
- Check status
$ git status # On branch master nothing to commit (working directory clean)
With Tags
If there are nested tag folders like tags/released/1.x/1.1.0, tags/released/1.x/1.2.0, tags/released/1.x/1.3.0, tags/released/2.x/2.0.1 and tags/released/2.x/2.2.0
, add --tags
(for branches, it's --branches
)
$ git svn clone --stdlayout --tags=tags/*/*/* --no-metadata -A users.txt --username=USERNAME https://svn.repo/some-parent-folder/project-folder project $ cd project $ git svn fetch
#### not necessary as it will be handled differently (by create tag and remove the svn tag) $ cp -Rf .git/refs/remotes/tags/* .git/refs/tags/ $ rm -Rf .git/refs/remotes/tags $ cp -Rf .git/refs/remotes/* .git/refs/heads/ $ rm -Rf .git/refs/remotes ###################################################################################
$ git branch -r
Then for each tag listed do:
$ git tag tagname tags/tagname $ git branch -r -d tags/tagname
$ git tag tag-name-for-git tags/tag-name-from-svn $ git branch -r -d tags/tag-name-from-svn
e.g.)
$ git tag 0.1.15 tags/released/0.x/some-app-0.1.15 $ git branch -r -d tags/released/0.x/some-app-0.1.15
- list tags
$ git tag -l
- remove old svn tags
$ rm -Rf .git/refs/remotes/tags
$ git remote add origin git@git-repo:project
* add user info to project/.git/config $ git config -e
[user] email = user@host
and remove [svn-remote "svn"] and [svn]
$ git push origin --all
It doesn't seem like the tags are pushed?
$ git push origin --tags