The excellent Git - SVN Crash Course is somewhat too succint on remote shared repositories and branching. Here I try to provide some of the missing necessary bits.
If you prefer to see it as a shell animation, download and run this script. You just need to keep closing the gitk window to see it animated.
mkdir bare-repo cd bare-repo git init --bare cd ..
git clone bare-repo annie cd annie gitk --all
echo 'hello' > README git add README git commit -m 'annie commits hello' # the commit is local only! it's not published yet! gitk --all
git push origin master:master # send our commits to the upstream repo (called 'origin') # we're specifically sending our master (the first one) to their master # shorter version: git push origin master cd ..
git clone bare-repo bob cd bob
echo 'bob adds hello' >> README
git commit README -m 'bob adds his hello' # note the fine-grained committing, specifying only the files we commit # you may also use 'git commit -a' to commit all modified files git push origin master
cd ..
cd annie git pull # get changes from upstream
git branch annies-experiment # note that we are *not* on the branch yet
git checkout annies-experiment # going to the new branch
cat README | sed 1iannie-adds-prefix > README.new mv README.new README git commit -a -m "annie's experiment"
cd ..
cd bob git pull # note that bob does not see annie's local branch at all
echo 'bob develops further' >> README git commit -a -m 'bob develops further'
git push origin master cd ..
cd annie git fetch
git checkout master
git merge origin/master # make our local master branch up-to-date
echo 'annie develops master further' >> README git commit -a -m 'annie develops further' # this commit was still only local
git push origin master # let's push our development upstream
cd ..
cd annie git push origin annies-experiment:annies-experiment # publish our branch in the shared repo # origin ... is the shared repo # annies-experiment (the former) ... is the local name of the branch # annies-experiment (the latter) ... is the remote name of the branch
cd ..
cd bob git fetch # bob came back from holiday and notices the master has evolved # and annie has published her branch
git checkout --track -b annies-experiment origin/annies-experiment # bob creates a local branch to track annie's branch in origin
cat README | sed 1ibob-adds-one-more-prefix > README.new mv README.new README git commit -a -m "bob joins annie's experiment" # this commit was still only local!
git push # try pushing all branches: # annies-experiment will succeed # master will be rejected because bob's master is out of date
cd ..
cd annie git checkout annies-experiment cat README | sed 1iannie-adds-one-more-prefix > README.new mv README.new README git commit -a -m "annies adds one more prefix" # this commit was only local
cd ..
cd annie git fetch # annie gets bob's updates and sees that bob has further developed her branch
git merge origin/annies-experiment # annies plans to merge bob's work and her work # but a conflict occurs
cat README | sed '1,5d;6iannie-and-bob-added-one-more-prefix' > README.new mv README.new README git commit -a -m "annies merges her and bob's work"
git push # annie pushes the merge upstream
cd ..
cd bob # first, bob makes all his local branches up to date git pull # only the current branch (annies-experiment) gets up to date
git checkout master
git pull # now also the master is up to date
git merge annies-experiment # we are on (local) master, modifying it to include (local) annies-experiment # the merge had no conflicts! awesome! # ...so a local commit happened right away, unlike above
git push # push the merge upstream
cd ..
cd annie git fetch # annie sees her branch was merged to the master => no need to stay alone
git checkout master # annie will work on the master now
git pull # and makes the master up-to-date