Git recipes
A collection of small useful recipes for using with Git
.
Sharing repositories
Use the command:
git init --bare --shared /srv/git/myrepo.git
Creates a repo with the following config:
core.bare = true
: make it a bare repocore.sharedrepository = 1
(same ascore.sharedrepository = group
): the repo directory and all directories later created in it will be managed by git to allow group read, write, and execute permissions (with the sgid bit set as well -- so as to work with users different primary group)receive.denyNonFastforwards = 1
: deny non fast-forward pushes to the repo
Make sure that the user and group ownership of the files is correct. You may need to
run chown -R
or chgrp -R
to correct this.
If you want to fine-tune the user, group, or other users' permissions, use
--shared=0NNN
, where NNN
are the standard user, group, and other bits for files
(the execute and sgid bits on directories will be managed appropriately by git). For
example, this allows read and write access to the user, and read-only access to the
group (and no access to other):
git init --bare --shared=0640 /srv/git/myrepo.git
This allows read and write access to the user and group (and no access to other):
git init --bare --shared=0660 /srv/git/myrepo.git
This allows read and write access to the user and group, and read-only access to other:
git init --bare --shared=0664 /srv/git/myrepo.git
This is the default.
Rewriting history
Rolling back the last commit
if nobody has pulled your remote repo yet, you can change your branch HEAD and force push it to said remote repo:
git reset --hard HEAD^
git push -f
Restoring changes
So in the event that you want to go back to a previous version of a file. First you must identify the version using:
git log $file
Once you know which commit to go to, do:
git checkout $hash $file
Then
git commit $file
User friendly version ids
Creating version ids Use:
git describe
Gives:
$tag-$commit_count-$hash
However for this to work, you need to have a good tag set and a good tag naming convention.
Branches
Main branch names:
- master - The main branch. Source code of HEAD always reflects production-ready status.
- develop or dev - Main dev branch. HEAD always reflects state with the latest development changes for the next release. This can sometimes be called the "integration branch" and used to generate automatic nightly builds.
Also a variety of supporting branches to aid parallel development between team members, ease tracking of features, prepare for production releases and to assist in quickly fixing live production problems. Unlike the main branches, these branches always have a limited life time, since they will be removed eventually. Creating a new branch:
git checkout -b new_branch develop
# Creates a branch called "new_branch" from "develop" and switches to it
git push -u origin new_branch
# Pushes "new_branch" to the remote repo
Listing branches
git branch # List all local branches
git branch -a # List local and remote branches
Merging branches
git checkout dev
# Switches to branch that will receive the commits...
git merge --no-ff "feature_branch"
# makes the a single commit (instead of replaying all the commits from the feature branch)
Deleting branches
git branch -d branch_name # Only local branches
git push origin --delete branch_name # Remote branch
git push origin :branch_name # Old format for deleting... prefix with ":"
Clean-up delete branches in remote repo from local repo...
git branch --delete branch
git remote prune origin
Tagging
Creating tags
Tag releases with
git tag -a $tagname -m "$descr"
This creates an annotated tag that has full meta data content and it is favored by Git describe.
Temporary snapshots
git tag $tagname
These are lightweight tag that are associated to a specific commit.
Sharing tags
By default are not pushed. They need to be exported with:
git push origin $tagname
or
git push origin --tags
To pull tags (if there aren't any)
git fetch --tags
Deleting tags
git tag -d $tagname # Local tags
git push --delete origin $tagname # Remote tags
git push origin :refs/tags/$tagname # Remote tags (OLD VERSION)
Rename a tag:
git tag new old
git tag -d old
git push origin :refs/tags/old
Setting up GIT
git config --global user.name "user"
git config --global user.email "email"
Other settings:
[http]
sslVerify = false
proxy = http://10.47.142.30:8080/
[user]
email = [email protected]
name = alex
Using ~/.netrc for persistent authentication
Create a file called .netrc
in your home directory. Make sure you sets permissions 600
so that it is only readable by user. With Windows, create a file _netrc
in your home directory. You may need to define a %HOME% environment variable. In Windows 7 you can use:
setx HOME %USERPROFILE%
or
set HOME=%HOMEDRIVE%%HOMEPATH%
The contents of .netrc
(or _netrc
) are as follows:
|machine $system
| login $user
| password $pwd
|machine $system
| login $user
| password $pwd
Creating new repositories
mkdir ~/hello-world
cd ~/hello-world
git init
# Creates an empty repository in ~/hello-world
touch file
git add file
git commit -m 'first commit'
# Creates a new file and commits locally
git remote add origin 'https://$user:[email protected]/$user/hello-world.git
# Creates a remote name for push/pull
git push origin master
# Send commits to remote
Creating a bare repo:
mkdir templ
cd templ
echo "Initial commit" > README.md
git add README.md
git commit -m"Initial commit"
git clone --bare .
Vendor Branches
Set-up
unzip wordpress-2.3.zip
cd wordpress
# Note, unzip creates this directory...
git init
git add .
git commit -m 'Import wordpress 2.3'
git tag v2.3
git branch upstream
# Create the upstream branch used to track new vendor releases
When a new release comes out:
cd wordpress
git checkout upstream
rm -r \*
# Delete all files in the main directory but doesn't touch dot files (like .git)
(cd .. && unzip wordpress-2.3.1.zip)
git add .
git commit -a -m 'Import wordpress 2.3.1'
git tag v2.3.1
git checkout master
git merge upstream
A variation of vendor branches is to sync with an upstream fork in github. Read this guide on how to do that: Syncing a fork on github
GIT through patches
Creating a patch:
... prepare a new branch to keep work separate ...
git checkout -b mybranch
... do work ...
git commit -a
.. create the patch from branch "master"...
git format-patch master --stdout > file.patch
To apply patch..
... show what the patch file will do ...
git apply --stat file.patch
.. displays issues the patch might cause...
git apply --check file.patch
.. apply with am (so you can sign-off)
git am --signoff < file.patch
Maintenance
git fsck
git gc --prune=now # Clean-up
git remote prune origin # Clean-up stale references to deleted remote objects
Submodules
Add submodules to a project:
git submodule add $repo_url $dir
Clone a project with submodules:
git clone $repo_url
cd $repo
git submodule init
git submodule update
Or in a single command (Git >1.6.5):
git clone --recursive $repo_url
For already cloned (Git >1.6.5):
git clone $repo_url
cd $repo
git submodule update --init --recursive
To keep a submodule up-to-date:
git pull
git submodule update
Remove sub-modules:
git submodule deinit $submodule
git rm $submodule # No trailing slash!
setting git email per repository
Navigate to the work repository, then at the root folder run the following command to change the email.
git config --local user.email [email protected]
Note: this command only affects the current repository. Any
other repositories will still use the default email specified in
~/.gitconfig
.
Alternatively, you can have different configurations based on a directory path by using:
Contents of $HOME/.gitconfig
[includeIf "gitdir:~/work/"]
path = .gitconfig-work
[includeIf "gitdir:~/personal/"]
path = .gitconfig-personal