name: inverse layout: true class: center, middle, inverse
Licensed under CC BY 4.0. Code examples: OSI-approved MIT license.
layout: false
- Distributed version control
- Non-bare and bare repositories
- Cloning repositories
- Collaboration with others
- Fetching changes from remote repositories
- Pushing changes to remote repositories
- Git implements a distributed version control
- All these topologies are possible
- In contrast to other version control tools we do not contribute to a repository through a lightweight working copy but rather by cloning the entire repository
- Until now we have met only non-bare repositories
$ git init # creates a non-bare repository- A non-bare repository contains
.gitand "the normal files" - We can checkout local branches
- We can and do work inside non-bare repositories
- We can create a bare repository
$ git init --bare # creates a bare repository- A bare repository contains only the
.gitpart - We never work inside a bare repository
- We can clone repositories
- We can clone on the same host
host1$ cd /path/to/repo
host1$ git init # creates non-bare
host1$ git clone /path/to/repo /path/to/clone # creates non-bare
host1$ git clone --bare /path/to/repo /path/to/clone-bare # creates bare- Or you clone from another machine via ssh (or via other protocols)
host2$ git clone ssh://user@host1/path/to/repo [/path/to/clone] # non-bare- A clone is a full-fledged repository
- We can clone again and again
- Typically we create a star-topology or tree-topologies or triangular topologies
- Think of
git cloneas ascp -r"plus" - We will see what the "plus" means
- By cloning we clone all commits, all branches, entire history
- We need a mechanism to communicate changes between the repositories
- We will pull or fetch updates from remote repositories
- There is a difference between pull and fetch and we will see what the difference is
- We will push updates to remote repositories
- We collaborate with other people through clones by pulling/fetching and pushing changes
- Everybody typically works on own clones
- Sometimes one person works on several clones (typically on different machines)
- We will only push to bare repositories
- Think of Dropbox as a clone which automatically pulls/pushes from/to a bare clone sitting somewhere on Dropbox servers
- Imagine there is a remote repository on host1
- We are ready to clone the repository
host2$ git clone ssh://user@host1/path/to/repo [/path/to/clone]- We clone the entire history, all branches, all commits
git clonecreates pointersorigin/masterandorigin/devoriginrefers to where we cloned from- It is a shortcut for
ssh://user@host1/path/to/repo
origin/masterandorigin/devare read-only pointers- They only move during
git pullorgit fetchorgit push - Only
git pullorgit fetchorgit pushrequire network - All other operations are local operations
- Remote repository receives a new commit
- Pointer is moved (pushed) by someone else (could be you)
- Nothing changes on the local repository until we pull/fetch these changes over the network
$ git fetch origingit fetch originupdatesorigin/masterandorigin/dev
$ git merge origin/master- In a second step we merge
origin/master(in this case fast-forward)
$ git fetch origin
$ git merge origin/master- This is equivalent to
$ git pull origin mastergit pullconsists of two operations: agit fetchfollowed by agit merge- Summary:
git pull origin masterfetchesmasterfromoriginand merges it - There is always a
git merge"hidden" ingit pull - Many people will simply
git pull, very careful people firstgit fetchand inspect the commits before merging them - With Git you typically merge several times a day without even noticing
- We can commit locally
- These commits are not visible to others until we
git push - Observe that
master,origin/master, andmasteron remote repository are 3 different pointers
$ git push origin master- Only now the remote
masteras well asorigin/mastermove
- We commit
d7and in the meantime remote receives commitc7from someone else - What happens if we
git pull origin master?
$ git pull origin master- First we fetched (
origin/mastermoved), then we mergedorigin/mastertomaster(mastermoved) - Local master and remote master are two different branches
- If they diverge, Git will merge them during
git pull
$ git pull --rebase origin master- You can avoid this using
--rebase - This will replay your unpublished local master commits at the end of
origin/master - Note how
d8changed tod8*
$ git checkout -b dev origin/dev- We create and switch to local branch
devtrackingorigin/dev
- If there is no local branch
devand there is a remote branchorigin/dev, then both are equivalent
$ git checkout -b dev origin/dev$ git checkout dev- As we commit to
devthe pointer moves whileorigin/devdoes not
$ git push origin dev- We have pushed
origin/devforward
- What if you have created a local branch and want to make it public?
- Simply push it upstream
$ git checkout -b cool-branch # create and switch to cool-branch
$ git commit # work and commit
$ git push -u origin cool-branch # push to origin and set as upstream- We can also delete remote branches
$ git push origin --delete cool-branchgit clonecopies everything and sets some pointers to remember where the clone came from
$ git remote -v
origin user@somehost:somerepo (fetch)
origin user@somehost:somerepo (push)- You communicate commits with
git fetch/git pullandgit push - All other Git operations are offline: you can work on a plane while your coworker is on vacation in North Korea
originrefers to where you cloned from (but you can relocate it)origin/foois a read-only pointer to branchfooon originoriginpointers only move when yougit fetch/git pullorgit push
- Branches are just pointers to commits
masterandorigin/masterare two different branchesHEADpoints to where we currently are
- We do some work on the local
masterand create two commits - Time arrow goes from left to right (commit arrows point to their parents)
- What happens if we try to
git push?
- In this case
origin/masterreceived no other commits - First we see a fast-forward merge (pointer
origin/mastersimply moves) - This is followed by a successful push
- However, what if
origin/masterreceives other commits in the meantime? git pushis rejected:
$ git push
To https://github.com/user/repo.git
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to 'https://github.com/user/repo.git'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes (e.g. 'git pull') before pushing again. See the
'Note about fast-forwards' section of 'git push --help' for details.- We now have two options to integrate the commits on
origin/master - First option:
git pull - A
git pullalways consists ofgit fetchandgit merge - In this case a fast-forward merge was not possible and a merge commit is automatically created
- Second option:
git pull --rebase - This moves our local commits after the commits on
origin/master - This operation creates new commits (marked asterisk)
- The new commits are rebased
- The source code after
git pullandgit pull --rebaseis the same - The history is different (no merge commit for
git pull --rebase) - It is possible to make
git pull --rebasedefault withgit config
- Real example
- A developer committed big changes to local master
- But he did not pull or push for several weeks
- When he tried to push, he could not because origin/master was out of date
- When he tried to pull in order to update origin/master there were conflicts everywhere
- After this experience he hated Git
- Explanation
- Local master and remote master are two different branches
- Local feature branch and remote feature branch are two different branches
git pullfetches and merges- If you never pull then the branches may diverge
git pulloften to stay in sync with upstream developmentgit pushwhenever you want other people to know about your changes- If you never
git pushothers will not see your changes - Nontrivial changes should not be done on master
- There is nothing special about the name
origin originis just an alias- Working with multiple remotes is not scary
- We can call these aliases as we like
- We can add and remove remotes
$ git remote add upstream https://github.com/foo/foo.git
$ git remote rm upstream
$ git remote add group-repo https://example.com/exciting-project.git
$ git remote rm group-repo- We synchronize remotes via the local clone
- To see all remotes
$ git remote -v- Centralized layout
- Decentralized layout
- Fork/pull-request layout
- Tags are also just pointers to commits
- While branches are mutable, tags are (typically) immutable
- Tags can carry extra annotation
- Always tag your releases
$ git tag # list all tags
$ git tag -a v1.4 -m 'my version 1.4' # create annotated tag
$ git tag v1.4 # create lightweight tag
$ git push origin v1.5 # share tag to upstream (origin)
$ git push origin --tags # push all tags$ ls -l .git/hooks/- Hooks are scripts that are executed before/after certain events
- They can be used to enforce nearly any kind of policy for your project
- There are client-side and server-side hooks
pre-commit: before commit message editor (example: make sure tests run)prepare-commit-msg: before commit message editor (example: modify default messages)commit-msg: after commit message editor (example: validate commit message pattern)post-commit: after commit process (example: notification)pre-rebase: before rebase anything (example: disallow rebasing published commits)post-rewrite: run by commands that rewrite commitspost-checkout: after successfulgit checkout(example: generating documentation)post-merge: after successful mergepre-push: runs duringgit pushbefore any objects have been transferredpre-auto-gc: invoked just before the garbage collection takes place
-
pre-receive: before accepting any references -
update: likepre-receivebut runs once per pushed branch -
post-receive: after entire process is completed -
Typical use:
- Maintenance work
- Refreshing of documentation/website
- Sanity checks
- Code style checks
- Email notification
- Rebuilding software packages
