Getting up speed with Git

Sharing your work
After mastering Git in a local repository, it's time to share the committed changes with others. One interesting fact comes up:
- Some statistics
-
KMess required 130MB for the subversion database, 33MB for a checkout of a single revision.
Git needs just 27MB for the full history, and additionally 14MB for a checkout.
In other words, a complete Git clone with full history available offline, is just slightly larger then a single subversion checkout.
Every user has it's own repository in Git.
Each repository is a full clone, with the entire history, compacted in such way it's actually smaller then the actual checkout of one or two commits.
Hence, every developer can work offline with full access to the entire project history. When needed, you can also share your work with other peers before sending the changes the main repository.
Establishing a connection
New projects
Projects need a location to host the repository. This can be a Gitorious or GitHub project for example. A self-hosted location can created with:
- Creating a shared repository at a server:
git init --bare projectname.git
Next, the local Git repository can be linked to it:
- Linking the local Git repository to a remote:
git remote add origin remote-url git push origin master
# push your local master to the origin
And you're set up!
Exising projects
To contribute to an existing project, clone the full repository:
- Cloning a repository:
git clone some-url
This will create a local repository, holding the full history of the remote project. The remote location is setup as origin automatically.
Fetching changes
New remote changes can be downloaded with:
- Downloading remote changes:
git fetch
The remote commits will actually live side-by-side in your repository, because they have different SHA1 identifiers. The commits also appear as just another branch in your repository, see:
- Inspecting fetched commits:
git log --all --graph --decorate
# alias it as 'git log-graph'
git log --oneline origin/master# display master branch of origin only
git branch -a# display local and remote branches
Integrating remote changes
Any local commits can be reaplied on top of the newly fetched changes:
- Connecting the remote branch:
git rebase origin/master
You can also do git merge instead.
Pull shortcut
The above steps can be done at once by the git pull command. The pull command uses git merge by default, but it can be changed:
- Letting git pull use rebase:
git pull --rebase
This can also be configured as default, in several ways:
- Setting git pull --rebase by default:
git config branch.master.rebase true
# master branch only
git config --global branch.autosetuprebase always# always use rebase
git config --global alias.up "pull --rebase"# or separate alias
Working at remote branches
To continue working from a remote branch, you'll have to create a local branch first. This is called a "tracking branch". The git clone command already does this for the master branch.
For a second branch, use:
- Shortcut
-
Note how this command is actually a shortcut for:
git branch -t branchname \
origin/branchname
git checkout branchname
- Start working on a remote branch:
git checkout -t origin/branch
Any commits at the tracking branch can eventually be pushed to the remote server.
Sending changes
Changes can be submitted with the push command. By default, all matching branches are pushed. To push one branch only, use:
- Pushing the master branch:
git push origin master
Aditionally, some notable parameters are:
--dry-run | Show what will be pushed |
--all | Push all branches |
--tags | Also push tags |
Out of date
The push command complains it can't do a "non fast-forward update". This is complex speak for "your repository is not in sync with the remote one".
Likely, the local branch is out of date or it's not merged with the remote branch. First run git fetch so the local repository is fully updated. With the log command, both branches will appear as disconnected:
- Displaying all branches:
git log --all --graph --decorate --oneline
This can be solved in several ways:
- Fixing a non-fast-forward:
git merge origin/master
# merge the remote branch
git rebase origin/master# base current commits on top of the remote
git reset origin/master# throw local changes away
This also happens when you've rewritten history of shared commits.
Extra: sending patches
A user without push access, can extract all commits as patches:
- Extracting patches:
git format-patch origin/master
The developer can apply these patches directly:
- Applying a single patch:
git apply 0001-test.patch git commit --author="Contributor <user@somewhere>
Applying many patches:
- Applying many patches:
git am *.patch
And finally, push the changes.
Internals: reference specifiers
The first argument of the push, pull and fetch commands indicates the remote alias or URL, the second is actually a "refspec". It has the notation localname:remotename.
This allows some weird syntax notations, you'll encounter sometimes:
- Push command syntax:
git push origin master:master
# local master to remote master
git push origin master# shortcut for master:master
git push origin :# all matching branches (the default)
git push origin :branch# nothing to remote branch -> deletes it
git fetch master:remotes/origin/master# fetch remote master to local remotes/origin/master
Like commit identifiers, branches have short names, for example:
master | = refs/heads/master |
origin/master | = refs/remotes/origin/master |
All these references can be found with internal commands:
- Internal commands to list references:
git show-ref git ls-remote . find .git/refs/ -type f
Coming up next
Sharing changes get nicer by rewriting history beforehand.
blog comments powered by Disqus