The following guide is deprecated and no longer valid for the new oliver.

Git Usage Guide

Git @ i10

Install Git

Git comes with Xcode 4 or later, or you can get the Git OS X Installer package. To resolve conflicts, you will need a diff tool like the one Xcode installs.

Upload repository

  1. Ignore Xcode project files (standard gitignore)
  2. Create bare clone of your local git project and prepare for server:
    cd GIT_PROJECT
    git clone --bare . ../PROJECT.git
    git update-server-info
  3. Copy PROJECT.git folder to oliver. Just mount afp://oliver.informatik.rwth-aachen.de/Public Review the Read me first document to find out where to place the git folder.
  4. Check out the repository from the server as described below (you can delete the local copy)

Check out repository via SSH

  1. (optional) Set up SSH public key authentication
  2. Check out repository:
    git clone ssh://oliver.informatik.rwth-aachen.de/Public/Research%20Projects/<project name>/Software/Sources/<git>.git

Hint: You might need to add your username for oliver if it differs from your local username. Add it right before

oliver.informatik[...]

with an @ before. Example:

git clone ssh://This email address is being protected from spambots. You need JavaScript enabled to view it./Public/Research%20Projects/<project name>/Software/Sources/<git>.git

When using Tower:

  1. Download Tower. We have a 30-user site license; ask Jan-Peter for details
  2. Select "Clone Remote Repository".
  3. In the Finder, drag the .git file from its folder on oliver to the RemoteURL textfield in Tower.
  4. Replace all whitespaces with %20.
  5. Replace everything before /Public/.... with ssh://oliver.informatik.rwth-aachen.de.
  6. Use your i10 login to download the repository.
  7. Double-click the resulting repository, switch to the "Browse" tab, then right-click the files there to edit them using your favorite editor.
  8. After changing a file, go to the Status tab, select the file to stage it, then select "Commit" to locally(!) commit the change.
  9. Now "Pull" to get any changes by others. If nothing happens, or merge happens automatically, you're fine, otherwise resolve merge conflicts manually.
  10. "Push" your merged changes into the main remote repository.
    NOTE: If you want to store a repository under your user account, use ssh://This email address is being protected from spambots. You need JavaScript enabled to view it./Volumes/Raid1/Users/USERNAME/.../REPOSITORY.git

Software Support

Versions is a SubVersion tool, so it won't work with Git. Alternatives are:

  • Tower: the recommended GUI for Mac OS X, we have licenses
  • GitKraken: free, available for all platforms, Aaron's recommendation
  • GitX: another GUI for Mac OS X
  • Sourcetree: ...
  • TortoiseGit: Windows Explorer integration
  • EGit: Eclipse plugin

Basic functions

Create local repository:

git init


Stage changes in files:

git add FILE1 FILE2...


Remove files:

git rm FILE1 FILE2...


See status (changed files):

git status


Commit staged changes (to the local repository):

git commit

Remote Repositories

Git stores its repository locally in the .git/ folder inside the versioned project - there is no central repository like in SubVersion. Instead, Git allows you to synchronize your repository with others directly, or through a central remote repository.

Create a remote repository:

Create a bare clone of your repository (copies only the repository):

git clone --bare PROJECT_PATH project.git


Upload project.git to

Check out remote repository

git clone ssh://oliver.informatik.rwth-aachen.de/Public/Research%20Projects/<your project name>/...


After checking out a remote repository, Git remembers the URL of the repository, which is then used to synchronize between yours and the remote.
Note that this is only true for the master branch by default!

Synchronize with remote repository

Pull changes from remote repository:

git pull


Push changes to the remote repository:

git push


Note that this is only true for the master branch if your other branches are not set up to track a remote branch (see below)!
Always pull before push!

Branches and Merging

Branches are used for parallel development, where you do not want your changes to affect other people's code. The master branch is the trunk.

Managing Branches

List (local|remote|all) branches (active is marked with *):

git branch [|-r|-a]



Create branch named foo (does not change the active branch):

git branch foo


Switch to branch foo:

git checkout foo



Set up a remote branch bar on the server that inherits from the master branch

git push origin master:bar



Set up a local branch foo that is tracking an existing branch bar on the server (i.e. pushing and pulling in foo will automatically target bar on the server):

git branch --track foo origin/bar



If you want an existing local branch foo (that does not exist on the server yet) to be published to the server under the name bar and make your local branch track that new server-side branch:

git push origin foo:bar
git checkout master
git branch --track -f foo origin/bar

The -f switch forces the local branch to be re-created with the new tracking info. Only do this if you do not have any pending changes on foo that have not been committed!

When you are done merging (see below) and are really done with your local branch foo, you may want to de-clutter your branch list and delete it:

git branch -d foo



If you are really done with a remote branch bar and do not even want it on the server anymore:

git push origin :bar

Merging

When you are done with the branch you need to merge it with the master:

  1. Commit local changes
  2. Switch to the target branch (master), then merge from the source branch:
    git checkout master
    git merge foo

Merges are automatically committed, unless there are conflicts.

Branching summary (when foo does not exist on server)

git push origin foo:bar -> push local foo as remote bar
git checkout master -> switch to master
git branch --track -f foo origin/bar -> create track to make push/pull easier

Rules of thumb

pull before push EVERY TIME!7

Reusable Resources

Default .gitignore

*.DS_Store
./build
*.xcodeproj/*.pbxuser
*.xcodeproj/*.mode1v3
*.xcodeproj/*.perspectivev3
xcuserdata


The first line is for the default Finder cache file.
The second line excludes Xcode's build folder.
The following three lines are for Xcode 3.
The last line is for Xcode 4.

up-to-date Alternative:
Use gitignore.io to create a .gitignore based on a big community on the web.
Used by a lot of famous companies ;-)

Convert SVN to GIT

If you installed git via ports you need to explicitly add svn support

port install git-core +svn +bash_completion



The following script requires git-svn. It takes two parameters via command line: URL for SVN (use svn+ssh protocol; https won't work.) and the name of your git repository (the new git repository will be created in your home directory)

#!/bin/bash
SVN_PATH=${1}
GIT_NAME=${2}

mkdir ~/tmp 
cd ~/tmp 
git svn init $SVN_PATH --no-metadata
git svn fetch 
cd ~
git clone --bare tmp $GIT_NAME.git
rm -rf ~/tmp



Example: suppose you have the script in svnToGit.sh and the URL is svn+ssh//oliver.informatik.rwth-aachen.de/svn/bla. The following code will convert your repository to ~/newGitRepository.git

./svnToGit.sh svn+ssh//oliver.informatik.rwth-aachen.de/svn/bla newGitRepository

Troubeshooting

Entry 'foo' not uptodate. Cannot merge

$ /tmp/repo2 git pull
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /tmp/repo1
   5851692..0a5b573  master     -> origin/master
Updating 5851692..0a5b573
error: Entry 'foo' not uptodate. Cannot merge.



This happens when you have local changes to files that have also been changed in the repository you are pulling from. You can remove the conflicting file if you do not want to keep your changes, then pull. If you want to keep the changes, you have to commit them first, then pull (potentially resulting in a conflict - see below).

Non-fast forwards and merge conflicts

Let's create a repository in directory repo1

$ /tmp mkdir repo1
$ /tmp cd repo1
$ /tmp/repo1 git init
Initialized empty Git repository in /tmp/repo1/.git/


Clone it to directory repo2

$ /tmp/repo1 cd ..
$ /tmp git clone repo1 repo2
Initialized empty Git repository in /tmp/repo2/.git/
warning: You appear to have cloned an empty repository.


Now we create a file "foo" in repo1 with the following contents:

A flea and a fly in a flue
Were caught, so what could they do?
Said the fly, "Let us flee."
"Let us fly," said the flea.
So they flew through a flaw in the flue.


Then we add this file and commit.

$ /tmp cd repo1
$ /tmp/repo1 git add foo
$ /tmp/repo1 git commit -am "Created file foo"
[master (root-commit) be64d03] Created file foo
 1 files changed, 5 insertions(+), 0 deletions(-)
 create mode 100755 foo


Then we create a file "bar" in repo2 and commit

$ /tmp/repo1 cd ../repo2
$ /tmp/repo2 echo whatever > bar
$ /tmp/repo2 git add bar
$ /tmp/repo2 git commit -am "Created file bar"
[master (root-commit) 993b876] Created file bar
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 bar


We now have two distinct modifications of the same data. Let's try to push the changes from repo2 to repo1.

$ /tmp/repo2 git push
To /tmp/repo1
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to '/tmp/repo1'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes before pushing again.  See the 'non-fast-forward'
section of 'git push --help' for details.


This is a non-fast forward, because our changes are not based on the current state of the target repository. We'll try to resolve this by pulling from repo1, thus incorporating repo1's changes into repo2, giving us a chance to handle any conflicts that might occur in the process.

$ /tmp/repo2 git pull
warning: no common commits
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /tmp/repo1
 * [new branch]      master     -> origin/master
Merge made by recursive.
 foo |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)
 create mode 100755 foo


Seems to have worked! Let's verify that.

$ /tmp/repo2 git status
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.
#
nothing to commit (working directory clean)


Alright, now we should be able to push to repo1.

$ /tmp/repo2 git push
Counting objects: 6, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (5/5), 516 bytes, done.
Total 5 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (5/5), done.
warning: updating the current branch
warning: Updating the currently checked out branch may cause confusion,
warning: as the index and work tree do not reflect changes that are in HEAD.
warning: As a result, you may see the changes you just pushed into it
warning: reverted when you run 'git diff' over there, and you may want
warning: to run 'git reset --hard' before starting to work to recover.
warning:
warning: You can set 'receive.denyCurrentBranch' configuration variable to
warning: 'refuse' in the remote repository to forbid pushing into its
warning: current branch.
warning: To allow pushing into the current branch, you can set it to 'ignore';
warning: but this is not recommended unless you arranged to update its work
warning: tree to match what you pushed in some other way.
warning:
warning: To squelch this message, you can set it to 'warn'.
warning:
warning: Note that the default will change in a future version of git
warning: to refuse updating the current branch unless you have the
warning: configuration variable set to either 'ignore' or 'warn'.
To /tmp/repo1
   be64d03..b5ee60e  master -> master


What the... okay... basically it says that while the repository in repo1 itself is up to date, the working copy in repo1 is not. The working copy will appear as if it is based on the new state of the repository, though. Let's verify:

$ /tmp/repo2 cd ../repo1
$ /tmp/repo1 git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       deleted:    bar
#


So we see, it seems as if we deleted the file "bar" (originating from repo2) in repo1 while in reality the files are just out of date. Let's bring that working copy up to speed:

$ /tmp/repo1 git reset --hard
HEAD is now at b5ee60e Merge branch 'master' of /tmp/repo1
$ /tmp/repo1 git status
# On branch master
nothing to commit (working directory clean)
$ /tmp/repo1 ls
bar  foo


Now we're talking. No changes according to git and file "bar" is present.

Now, let's modify the repositories asynchronously again, but this time we'll introduce a conflict by modifying the same line twice in both repositories and commit (we change line 1 in repo1, line 5 in repo2 and line 3 in both).

$ /tmp/repo1 cat foo
A flea and a fly in a flue                   # repo1
Were caught, so what could they do?
Said the fly, "Let us flee."                 # repo1
"Let us fly," said the flea.
So they flew through a flaw in the flue.
$ /tmp/repo1 git commit -am "foo changed in repo1"
[master 4f2f9d5] foo changed in repo1
 1 files changed, 2 insertions(+), 2 deletions(-)
$ /tmp/repo1 cd ../repo2
$ /tmp/repo2 cat foo
A flea and a fly in a flue
Were caught, so what could they do?
Said the fly, "Let us flee."                 # repo2
"Let us fly," said the flea.
So they flew through a flaw in the flue.     # repo2
$ /tmp/repo2 git commit -am "foo changed in repo2"
[master 4d5a6dd] foo changed in repo2
 1 files changed, 2 insertions(+), 2 deletions(-)


We don't even try to push this time but pull right away.

$ /tmp/repo2 git pull
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /tmp/repo1
   b5ee60e..4f2f9d5  master     -> origin/master
Auto-merging foo
CONFLICT (content): Merge conflict in foo
Automatic merge failed; fix conflicts and then commit the result.


Houston, we have a conflict. Git has joined the two versions and marked the conflicting differences for us:

$ /tmp/repo2 cat foo
A flea and a fly in a flue                   # repo1
Were caught, so what could they do?
<<<<<<< HEAD
Said the fly, "Let us flee."                 # repo2
=======
Said the fly, "Let us flee."                 # repo1
>>>>>>> 4f2f9d50a5544d58354398fd9ad6abb5211faf27
"Let us fly," said the flea.
So they flew through a flaw in the flue.     # repo2


We should now edit the file appropriately ("fix conflicts", as instructed). Since we hate limericks, this is easy:

$ /tmp/repo2 echo "Not funny" > foo


We continue to follow git's instructions and "commit the result":

$ /tmp/repo2 git commit -am "Resolved a conflict, once and for all"
[master 158c9f3] Resolved a conflict, once and for all
$ /tmp/repo2 git status
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.
#
nothing to commit (working directory clean)


Done. Now push the changes to repo1 and we see something familar:

$ /tmp/repo2 git push
Counting objects: 10, done.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 640 bytes, done.
Total 6 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (6/6), done.
warning: updating the current branch
warning: Updating the currently checked out branch may cause confusion,
warning: as the index and work tree do not reflect changes that are in HEAD.
warning: As a result, you may see the changes you just pushed into it
warning: reverted when you run 'git diff' over there, and you may want
warning: to run 'git reset --hard' before starting to work to recover.
warning:
warning: You can set 'receive.denyCurrentBranch' configuration variable to
warning: 'refuse' in the remote repository to forbid pushing into its
warning: current branch.
warning: To allow pushing into the current branch, you can set it to 'ignore';
warning: but this is not recommended unless you arranged to update its work
warning: tree to match what you pushed in some other way.
warning:
warning: To squelch this message, you can set it to 'warn'.
warning:
warning: Note that the default will change in a future version of git
warning: to refuse updating the current branch unless you have the
warning: configuration variable set to either 'ignore' or 'warn'.
To /tmp/repo1
   4f2f9d5..158c9f3  master -> master


The resolution is of course the same:

$ /tmp/repo2 cd ../repo1
$ /tmp/repo1 git reset --hard
HEAD is now at 158c9f3 Resolved a conflict, once and for all
$ /tmp/repo1 cat foo
Not funny


That's it for now!

Guides


Attachments:
File Description File size Downloads Last modified
gitignore   0 kB 877 2011-11-16 12:13

We use cookies on our website. Some of them are essential for the operation of the site, while others help us to improve this site and the user experience (tracking cookies). You can decide for yourself whether you want to allow cookies or not. Please note that if you reject them, you may not be able to use all the functionalities of the site.