distributed version control: version and help | local and remote repository | working directory | track and commit | branch and merge | history | push and pulll | configuration files | external repositories | packaging | integrity check and garbage collection
version control: svn | cvs | rcs
archive and patch tools: diff | cpio | diff3 | ar | tar | patch | zip | diffstat | jar | rsync | colordiff
| version and help | ||
|---|---|---|
| git | hg | |
| show version | $ git version | $ hg version |
| list subcommands | $ git help -a commonly used subcommands only: $ git help |
$ hg [-v] help -v: show aliases and global options |
| get help for subcommand | $ git help CMD | $ hg help CMD |
| list topic guides | $ git help -g | $ hg help |
| get help for topic | $ git help TOPIC | $ hg help TOPIC |
| local and remote repository | ||
| git | hg | |
| create repository from a directory | $ git init [DIR] | $ hg init [DIR] |
| create repository with no working directory | $ git init --bare [DIR] puts repo in DIR |
none |
| clone entire repository | $ git clone [-b BRANCH] [-o NAME] [--depth NUM] URL [DIR] -b: checkout BRANCH in working dir -o: assign NAME to remote repo --depth: copy commit history to depth NUM |
|
| repository url formats | ssh://[user@]host.xz[:port]/path/to/repo.git git://host.xz[:port]/path/to/repo.git http[s]://host.xz[:port]/path/to/repo.git ftp[s]://host.xz[:port]/path/to/repo.git rsync://host.xz/path/to/repo.git /path/to/repo.git file:///path/to/repo.git |
local/filesystem/path[#revision] file://local/filesystem/path[#revision] http://[user[:pass]@]host[:port]/[path][#revision] https://[user[:pass]@]host[:port]/[path][#revision] ssh://[user@]host[:port]/[path][#revision] |
| clone branch from repository | $ hg clone [-r REV|-b BRANCH] … URL [DIR] | |
| clone repository; new repository has no working directory | $ git clone --bare URL [DIR] puts repo in DIR |
$ hg clone -U URL [DIR] puts repo in DIR/.hg |
| list remote repositories | $ git [[-v] show] remote -v: show url of remote |
$ hg paths |
| add remote repository | $ git add [-t BRANCH] … NAME URL $ git add [-m BRANCH] NAME URL |
edit the [paths] section of .hg/hgrc |
| remove remote repository | $ git rm REMOTE | |
| rename remote repository | $ git rename REMOTE NAME | |
| show remote repository details | $ git remote show [-n] REMOTE -n: do not connect to remote repo |
|
| edit remote repository details | $ git remote set-head REMOTE (-a|-d) BRANCH $ git remote set-url --add REMOTE URL $ git remote set-url --delete REMOTE URL $ git remote set-branches REMOTE [--add] BRANCH … |
|
| working directory | ||
| git | hg | |
| check out version | $ git checkout [-f] (BRANCH|TREEISH) -f: overwrite changes in working dir and index |
$ hg update [-c|-C] -r REV -c: fail if changes in working dir -C: discard changes in working dir |
| list modified files | $ git status [-s] [--ignored] [PATH] … -s: short format --ignored: also files excluded by .gitignore |
$ hg status [PATH] |
| ignore file | .gitignore | .hgignore |
| check out specific files | $ git checkout [TREEISH] -- PATHSPEC … | $ hg revert [-C] [-r REV] PATH … -C: do not create backups w/ .orig suffix |
| check out from index | $ git checkout -p PATHSPEC … | no index |
| clear index | $ git reset | |
| clear index and working directory | $ git reset --hard | $ hg revert -C -a |
| list or remove untracked files | $ git clean (-f|-n) -f: remove untracked files -n: list untracked files |
$ hg purge [-p] -p: remove untracked files without -p untracked files are listed |
| move working directory changes to shelf | $ git stash [save [STR]] | $ hg [-n STR] shelve |
| list sets of changes in shelf | $ git stash list | $ hg shelve --list [-p] -p: show each set of changes as diff |
| show set of changes in shelf as diff | $ git stash show [STASH] | none |
| restore changes from shelf | $ git stash pop [STASH] | $ hg unshelve [STR] |
| delete set of changes from shelf | $ git stash drop [STASH] | $ hg shelve -d STR |
| clear shelf | $ git stash clear | $ hg shelve --clear |
| track and commit | ||
| git | hg | |
| track files | files are not tracked; changes must be added to staging area before each commit | $ hg add PATH … |
| track files matching pattern | $ hg add -I PATTERN | |
| track all files in working directory | $ hg add | |
| add modified or new files to staging area | $ git add PATHSPEC … -u: files already under version control only |
working directory is the staging area |
| add part of modified file to staging area | $ git add -e PATH | |
| track any new files in working directory, and remove any tracked files not in working directory | $ hg addremove [PATH] … | |
| remove files from working directory and next commit | $ git rm [-f] PATH … -f: force if changed in index |
$ hg remove [-f] PATH … -f: force if added or changed |
| remove files matching pattern | $ git rm [-f] PATHSPEC … -f: force if changed in index |
$ hg remove [-f] -I PATTERN -f: force if added or changed |
| remove files in next commit which are no longer in working directory | $ hg remove -A PATH … | |
| mark file to be removed in next commit without removing from working directory | $ hg forget PATH … | |
| remove subdirectory from working directory and next commit | $ git rm -r DIR | $ hg remove DIR |
| remove files from index | $ git rm --cached FILE … | |
| copy files from head to index | $ git reset -p FILE … | |
| copy files from index to working directory | $ git checkout -p PATH … | |
| move file in working directory and next commit | $ git mv OLDPATH NEWPATH | $ hg rename OLDPATH NEWPATH |
| move files into directory | $ git mv PATH … DIR | $ hg rename PATH … DIR |
| copy file in working directory and next commit | $ hg copy (-A|-f) SRC_PATH DEST_PATH -A: if file already copied -f: if target is tracked |
|
| show difference between staging area and head | $ git diff --cached [PATHSPEC …] | $ hg diff [PATH …] |
| show difference between working directory and staging area | $ git diff [PATHSPEC …] | working directory and staging area are the same |
| diff options | --name-only: list modified file names --name-status: status (M, A, D, R, ..) and modified file names --stat: histogram of changes by file --dirstat: histogram of changes by directory --word-diff: show changes to line inline --word-diff-regex=REGEX: set regex used by --word-diff -W: show entire modified function in context -R: reverse direction of diff -w: ignore whitespace differences --ignore-blank-lines: ignore blank lines --quiet: no output; exit status 1 if changes, otherwise 0 |
--stat: histogram of changes by file -p: show entire modified function in context -U NUM: show NUM lines of context --reverse: reverse direction of diff -w: ignore whitespace differences -b: ignore blank lines -X PATTERN: exclude files matching fileglob -S: recurse into subrepos |
| grep staging area | $ git grep --cached [-i] [-v] [-E|F|P] [-h|H] [-l|L] [-n] \ -e STR TREEISH [--] PATHSPEC |
|
| commit changes in staging area | $ git commit [-a] [-m STR] -a: add all modified files with version history to staging area before commit. |
$ hg commit [-m STR] |
| commit changes to selected files in staging area | $ git commit [-m STR] PATH … | $ hg commit [-m STR] PATH … |
| commit changes in working directory | $ hg commit -A [-m STR] | |
| amend most recent commit | $ git commit --amend | $ hg commit --amend |
| change author of most recent commit | $ git commit --amend --author=STR | $ hg commit --amend -u STR |
| commit identifiers | 40 hex digit hashes, e.g: bbf3837d6c9bb54f11a4c620a1c81975156c2a49 A prefix can be used to refer to a commit if it uniquely specifies it; often an 8 digit prefix is sufficient. HEAD refers to the most recent commit of the current branch. |
Each revision has a 40 hex digit hash and a sequential integer identifier. The hash is unique across all repositories, but the sequential integer is local to the repository. A prefix can be used to refer to a revision if it uniquely specifies it; often an 8 digit prefix is sufficient. A period . refers to the parent revision of the working directory. tip refers to the most recent revision in the repository. |
| other ways to refer to commits | A circumflex postfix can be used to refer to the parent commit of a commit, e.g. bbf3837d6^ The circumflex can be used multiple times to refer to a grandparent, great-grandparent, and so on: bbf3837d6^^ bbf3837d6^^^ An alternative to multiple circumflexes is tilde notation: bbf3837d6~2 bbf3837d6~3 when a commit has multiple parents (i.e. the commit is a merge), use a circumflex followed by a number: bbf3837d6^2 |
|
| resolve commit notation | $ git rev-parse COMMIT e.g. to get commit id of parent of tip: git rev-parse HEAD^ |
|
| create commit which reverts another commit | $ git revert [-n] COMMIT -n: no commit, just change working directory |
$ hg backout -r REV |
| create commit which reverts a merge commit | $ git revert [-n] -m NUM COMMIT NUM is the number of the parent (e.g. 1, 2, …) to restore |
|
| create commits which revert a sequence of commits | $ git revert [-n] COMMIT1..COMMIT2 reverts commits from COMMIT1 up to but not including COMMIT2. Use triple dots ... to include COMMIT2. |
|
| tag a commit | $ git tag [-f] NAME [COMMIT] -f: replace existing tag with same NAME if no commit specified, HEAD is tagged |
$ hg tag [-r REV] NAME |
| delete a tag | $ git tag -d TAG | $ hg tag --remove NAME |
| list tags | $ git tag | $ hg tags |
| branch and merge | ||
| git | hg | |
| current branch | $ git rev-parse abbrev-ref HEAD | |
| list branches | $ git branch [-r|-a] -r: list remote tracking branches -a: list local and remote tracking branches |
$ hg bookmarks |
| list branches by commit | $ git branch (--contains|--merged) COMMIT --contains: branches descended from COMMIT --merged:branches ancestors of COMMIT |
|
| checkout branch | $ git checkout BRANCH -f: discard changes in index and working directory |
$ hg update BRANCH -C: discard changes in working directory -c: fail if changes in working directory |
| move branch head without changing working directory | $ git reset [--soft] COMMIT | |
| create new branch by cloning branch | $ git checkout -b NAME [BRANCH] | $ hg bookmarks NAME |
| create a tracking branch | $ git branch --track NAME [BRANCH] | |
| create a branch from a commit | $ git branch NAME COMMIT | $ hg bookmarks -r REV NAME |
| rename a branch | $ git branch -m BRANCH NAME | $ hg bookmarks -m NAME1 NAME2 |
| delete a branch | $ git branch (-d|-D) BRANCH -d: fail if tracking branch with unmerged commits -D: delete even if unmerged commits exist |
$ hg bookmarks -d NAME |
| list "dedicated commit" branches | $ hg branches | |
| show current "dedicated commit" branch | $ hg branch | |
| change branch of next commit | $ hg branch BRANCH | |
| list branch tips | $ hg heads [-c] -c: include closed tips |
|
| close branch tip | $ hg commit --close-branch | |
| merge | $ git merge [--squash] COMMIT … --squash: make changes to index and working directory only; do not create a commit |
$ hg merge [[-r] REV] Only modifies working directory; must be following by hg commit to create a new changeset. |
| show conflicts | $ git status | $ hg resolve -l |
| mark file with conflicts as resolved | $ git add PATH | $ hg resolve PATH |
| unmark file with conflicts as resolved | $ hg resolve -u PATH | |
| abort merge | $ git merge --abort | $ hg update -C |
| rebase current branch | $ git rebase BRANCH | |
| continue rebase | $ git rebase --continue | |
| abort rebase | $ git rebase --abort | |
| squash commits | $ git rebase -i COMMIT commits after COMMIT can be squashed |
|
| apply commit to current branch | $ git cherry-pick COMMIT | $ hg graft -r REV |
| continue cherry pick | $ git cherry-pick --continue | |
| abort cherry pick | $ git cherry-pick --abort | |
| create detached head from branch and sequence of commits | $ git rebase —onto BRANCH COMMIT1 COMMIT2 | |
| history | ||
| git | hg | |
| write version of file to standard out | $ git show COMMIT:FILE | $ hg cat -r REV FILE |
| annotate lines of file with commit info | $ git blame [-l] [-s] [-s] PATH [COMMIT] -l: show full commit id (default is 8 chars) -s: suppress author name and timestamp -w: ignore whitespace differences |
$ hg annotate -cudln [-r REV] [PATH] -c: changeset -u: author -d: date -l: line number -n: local revision number |
| commits which are ancestors of head/tip | $ git log [--parents] --parents: after commit identifier show parent commit identifiers |
$ hg log |
| commits as graph | $ git log --graph | $ hg log -G |
| first parent history | $ git log --first-parent | |
| chronological order | $ git log --reverse | |
| all commits in repository | $ git log [--source] --all --source: print ref name after each commit |
|
| limit commits | $ git log [--skip=NUM] -(n NUM|-NUM) --skip: skip first NUM commits |
|
| commits which touched files | $ git log [--follow] [--] PATH … --follow: follow renamed files --: prevent interpreting PATH as option |
$ hg log [-f] PATH … -f: follow copied and renamed files |
| commits which touched lines | $ git log -L NUM,NUM:PATH | |
| one line commits | $ git log --oneline | |
| format string for commit | $ git log —pretty=format:FORMAT format string specifiers: %H commit hash %h abbrev. commit hash %T tree hash %t abbrev. tree hash %P parent hash(es) %p abbrev. parent hash(es) %s subject %b body %an author name %ae author email %ad author date %cn committer name %ce committer email %cd committer date %n newline %% percent sign |
|
| show commit diffs | $ git log -p | |
| show commits touching lines matching regular expression | $ git log -p [--pickaxe-all] -G REGEX | $ hg grep PATTERN |
| grep commit messages | $ git log --grep=REGEX | $ hg log --keyword STR case insensitive search; also searches source |
| show changes to head | $ git reflog The output format is: <commit> HEAD@{<num>} <description> <num> is the number of changes since HEAD was at <commit>. HEAD@{<num>} can be used as an alias for <commit>. This outputs reflog info in log style: $ git log -g |
|
| difference between commit and its parent | $ git diff [--name-only] COMMIT^ COMMIT [--] [PATH …] | $ hg diff -c REV [PATH …] |
| difference between two comits | $ git diff [--name-only] COMMIT1 COMMIT2 [--] [PATH …] | $ hg diff -r REV1 -r REV2 [PATH …] |
| diff options | --name-only: list modified file names --name-status: status (M, A, D, R, ..) and modified file names --stat: histogram of changes by file --dirstat: histogram of changes by directory --word-diff: show changes to line inline --word-diff-regex=REGEX: set regex used by --word-diff -W: show entire modified function in context -R: reverse direction of diff -w: ignore whitespace differences --ignore-blank-lines: ignore blank lines --quiet: no output; exit status 1 if changes, otherwise 0 |
--stat: histogram of changes by file -p: show entire modified function in context -U NUM: show NUM lines of context --reverse: reverse direction of diff -w: ignore whitespace differences -b: ignore blank lines -X PATTERN: exclude files matching fileglob -S: recurse into subrepos |
| grep commit | $ git grep [-i] [-v] [-E|F|P] [-h|H] [-l|L] [-n] \ -e STR TREEISH [--] PATHSPEC |
|
| start bisection | $ git bisect BAD_COMMIT GOOD_COMMIT | |
| mark bisection commit as good | $ git bisect good | |
| mark bisection commit as bad | $ git bisect bad | |
| mark bisection commits automatically | $ git bisect run SCRIPT [ARG]… Exit status of 0 indicates a good commit. Exit status of 125 indicates an untestable commit. Any other status in the range 1…127 indicates a bad commit. |
|
| show bisection decisions | $ git bisect log | |
| terminate bisection | $ git bisect reset | |
| push and pull | ||
| git | hg | |
| pull commits from remote | $ git fetch [-f] [-t] [-p] [REPO] -f: force if update not a fast-forward -t: copy tags -p: remove local references gone from remote Pulls from origin if REPO not specified. Updates remote tracking branches per refspec of REPO in .git/config. |
$ hg pull [-u] [SOURCE] -u: update working directory to most recent changeset Pushes all revisions in local repository not on remote repository. If no SOURCE specified, uses value of default in the [paths] section of .hg/hgrc. |
| pull commits from remote for branch | $ git fetch [-f] [-t] [-p] REPO REFSPEC | $ hg pull (-b BRANCH|-B BOOKMARK|-r REV) … [SOURCE] -b: pull revisions on BRANCH and parents -B: pull BOOKMARKed revision and parents -r: pull REV and parents |
| pull commits from multiple remotes | $ git fetch [-f] [-t] [-p] (--all|--multiple REPO …) | |
| show remote commits available for pulling | $ hg incoming | |
| pull commits from remote and merge current branch with remote head | $ git pull [-f] REPO [REFSPEC] | |
| push commits to remote | $ git push [-f] [--prune] [--tags] [REPO] | $ hg push [-f] [SOURCE] |
| push commits to remote for branch | $ git push [-f] [-u] REPO [BRANCH] … | $ hg push [--new-branch] (-b BRANCH|-B BOOKMARK|-r REV) … [SOURCE] |
| delete remote branches | $ git push --delete REPO BRANCH … | |
| show commits which have not been pushed | $ hg outgoing | |
| move commits by archive | $ git bundle | $ hg bundle $ hg unbundle |
| configuration files | ||
| git | hg | |
| repository config file | .git/config | .hg/hgrc |
| user config file | ~/.gitconfig | ~/.hgrc |
| show config options | $ git help config | $ hg help config |
| set config value when cloning | $ git clone [-c SECTION.KEY=VAL] URL [DIR] | |
| list configuration settings | $ git config -l [--global] | $ hg showconfig |
| show specific configuration setting | $ git config —get [global] SECTION.KEY | |
| external repositories | ||
| git | hg | |
| external repository file | .gitmodules | .hgsub |
| external repository file format | [submodule "vendor/modules/system"] path = vendor/modules/system url = ../dm-kohana-core.git |
|
| add submodule | $ git submodule add URL PATH Records submodule in .gitmodules. If PATH does not exist, URL is cloned there. |
|
| register submodules | $ git submodule init Copies data from .gitmodules in index to .git/config. |
|
| $ git submodule update | ||
| clone repository and external repositories | $ git clone --recursive URL | |
| packaging | ||
| git | hg | |
| create tarball | $ git archive --format=tar TREEISH > repo.tar | $ hg archive -t tar ../NAME.tar |
| create gzipped tarball | $ git archive --format=tgz TREEISH > repo.tgz | |
| create zip archive | $ git archive --format=zip TREEISH > repo.zip | |
| create a patch | $ git format-patch ??? | $ hg export ??? |
| apply patch | $ git apply ??? | $ hg import ??? |
| integrity check and garbage collection | ||
| git | hg | |
| integrity check | $ git fsck | $ hg verify |
| garbage collection | $ git gc | none |
| _______________________________________________ | _______________________________________________________________________ | _______________________________________________________________________ |
Metasyntactic Variables
| git | |
|---|---|
| BRANCH | the name of a branch. |
| CMD | the name of a version control command: the first argument of the base command. |
| COMMIT | the HASH for a commit. A commit can be referenced indirectly via a branch or tag name or via commit notation. The symbolic references HEAD or FETCH_HEAD can also be used to reference commits. |
| DIR | a directory on the file system. In some cases it must exist; in others it will be created. |
| FILE | a regular file on the file system. In some cases it must exist; in others it will be created. |
| HASH | a 40 digit hex string used as an identifier for something in the object database. |
| HEAD | the literal string HEAD. |
| NAME | a name for an entity which will be created. Usually there are restrictions on the characters that can be used. |
| PATH | a path on the file system. In some cases it must exist; in others it will be created. |
| PATHSPEC | like a file glob pattern, except that ? and * can match the directory separator: /. Characters special to the shell must be escaped. |
| REFSPEC | [+]SRC_REF:DEST_REF where SRC_REF and DEST_REF are ref paths relative to the .git directory. SRC_REF is on the remote repository in a fetch or a pull and on the local repository in a push. An asterisk can be used in place of a component of the relative path to match everything in the directory. If the SRC_REF has an asterisk, the DEST_REF must also have one. A plus sign prefix + is used to indicate that the update should be made even when it is not a fast-forward. If the SRC_REF is the empty string, then the DEST_REF is deleted. Leading components of SRC_REF or DEST_REF can be omitted if no ambiguity results. |
| REMOTE | the name of a remote. |
| REPO | A REMOTE or a URL. |
| STASH | stash identifier format: stash@{0}, stash@{1}, … |
| STR | a string. There are no restrictions on the characters that can be used, but if they include whitespace or characters special to the shell they must be escaped or quoted. |
| TREEISH | the HASH for a tree, a commit, or a tag. If the HASH is for a commit or a tag the tree in the commit is used. |
| URL | a url for a repository. |
| hg | |
| BRANCH | the name of a branch. |
| CMD | the name of a version control command: the first argument of the base command. |
| DIR | a directory on the file system. In some cases it must exist; in others it will be created. |
| FILE | a regular file on the file system. In some cases it must exist; in others it will be created. |
| NAME | a name for an entity which will be created. Usually there are restrictions on the characters that can be used. |
| PATH | a path on the file system. In some cases it must exist; in others it will be created. |
| PATTERN | a file glob pattern. The metacharacters ?, *, and ** are supported. Characters special to the shell must be escaped. |
| REV | the revision number for a changeset. It can be either the local revision number, which is a small decimal integer, or the 12 hex digit universal revision number. |
| SOURCE | A URL or a name for a URL in the [paths] section of the .hg/hgrc file |
| STR | a string. There are no restrictions on the characters that can be used, but if they include whitespace or characters special to the shell they must be escaped or quoted. |
| URL | a url for a repository. |
Help
show version
list subcommands
get help for subcommand
list topic guides
get help for topic
Local and Remote Repository
When a set of files is edited, we can view the set of files as a sequence of versions or revisions which are ordered in time. A repository is a record of the versions of a set of files; it permits recovering the set files as they were at any of the recorded points in time.
A working directory (q.v the working directory of a process) can contain a copy of one of the file set versions; it can also be edited to create a new version of the file set. A commit is the act of recording the new version of the file set in the repository. This is done by comparing the working directory with the previous version or an empty file set in the case of an initial commit. The commit can also be regarded as the difference—that is, the output of diff -r—between the previous and the new version. This difference is also called the changeset.
When calculating the changeset, the version control system may ignore files in the working directory which are not tracked files.
A set of files and directories under version control is called a repository.
git
A file or directory under version control has one or more versions. One adds new versions to the repository by making a commit. The set of all files and directories in the repository can also be seen as having versions; these versions are called commits; they consist of at most one version of each file or directory in the repository.
hg
A file or directory under version control has one or more revisions. One adds new revisions to the repository by making a commit. The set of files and directories in the repository can also be seen as having revisions; these revisions are called changesets.
Working Directory
check out version
git:
These two commands appear to do the same thing:
$ git checkout -f COMMIT
$ git reset --hard COMMIT
list modified files
ignore file
git
A list of file patterns, one per line. The patterns specify files that git status and git add should ignore. Shell glob syntax (i.e. the asterisk: *) can be used.
A .gitignore can be placed in any directory in the repository. The rules in a given .giitignore file will only apply to the current directory and the directories beneath it.
Lines starting with a pound sign: # are ignored.
A pattern starting with an exclamation point: ! will negate a pattern. This can be used to include files that were excluded by a pattern higher in the file matching a broader set of files.
hg
Unlike .gitignore, an .hgignore file must be in the root of the working directory.
The format is one Perl regular expression per line. All files which match the regular expression will be ignored.
Comments start with the pound sign: #
It is also possible to use glob syntax:
# regexp to ignore twiddle files:
~$
# glob to ignore compiled python files:
syntax: glob
*.pyc
# additional patterns will use regexp format:
syntax: regexp
Track and Commit
git
Git keeps copies of all versions of files and directories that have been committed, as well as the commits themselves, in the directory .git/objects. All objects are identified by their 40 character SHA-1 checksum called the hash. There are three types of git objects in this directory: a blob, which is the contents of a file. A tree, which corresponds to file system directory; it contains the file system name of the objects, which can be blobs (regular files) or trees (directories) and their hashes. Finally, a commit contains the top level tree for the commit and the parents of the commit. There will be zero parents for the initial commit and more than one parent for a commit which was created by a merge. Git stores a separate, albeit compressed, copy of each version of a file, tree, or commit in the .git/objects directory.
The git cat-file -p HASH command, though not needed for day-to-day use, provides a way to inspect a git object. It shows the additional information stored in trees and commits which we have not mentioned here.
hg
Mercurial uses a storage format called a revlog to store the versions of a file. Most revlogs are kept in .hg/store/data. A revlog usually consists of two files: one with an .i suffix and another with a .d suffix. If the file is small and has little or no history, the revlog might consist of only a .i file. A revlog which tracks the history of a file is called a filelog. When the file is first committed, it is written to the filelog. Each time a commit is made which alters it, a delta describing the change is appended to the file. Thus, to fetch the current version of a file, all the deltas must be applied in order to the original version of the file. As a performance optimization, Mercurial will sometimes append the full version of the file to a filelog. Thus, when reconstructing the current version, one need only apply delta starting from the last time the full version was stored.
Mercurial stores a manifest for each revision of the repository. A reviion of the repository is called a changeset. The manifest is list of the pathnames relative to the root of all files in the changeset. Rather than store the manifests in separate files, all the manifests for the repository are stored in a revlog in .hg/store. Each time a new changeset is added to a repository by a push, pull, or commit command, it is assigned a local revision number which is the order in which it was appended to the local manifest revlog. If the changeset was pulled from a different repository, the local revision numbers might not match.
Information about changesets is also stored in the changelog, which is another type of revlog. The changelog has a pointer to manifest revision, pointers to parents of the changeset, and information about the committer.
git
Git has three types of objects: commits, trees, and blobs. Each is assigned a unique hash ID which is a 40 digit hex string. The identifier is called the hash, SHA1, object name, or object identifier with no difference in meaning. When the underlying object is a commit or tree it is also called a tree-ish.
Commit hashes are the hashes the user most commonly sees and needs to reference. Only as many of the digits that are necessary to uniquely identify an object in the object database need to be provided to a git command; usually the first 6 or 7 is sufficient.
HEAD is a special name which refers to the most recent commit of the current branch. It is stored in .git/HEAD. The previous commit is HEAD^ and the commit before that is HEAD^^. The is also numerical notation: HEAD~4 is 4 commits ahead of HEAD. If HEAD is the result of a merge, then the antecedents can be be referenced with HEAD^1 and HEAD^2.
hg
In Mercurial, every commit is assigned two identifiers: a local revision number and a universal changeset identifier. The local revision number is a small integer that is unique only to the local repository. The first local revision number issued is zero, and it increments with each local commit. The changeset identifier is a twelve digit hex number which is unique across all repositories.
The -r option is used to pass a mercurial commit identifier to a command. The argument can be a local revision number, a changeset identifier, or both separated by a colon.
move file in working directory and next commit
It is desirable for a version control system to track file name changes. Otherwise commands like blame and log when used on a single path will not show activity before the name change. If the version control system is aware of a name change, it can correctly handle the case when merging where the name was changed on one branch and edited on the other.
git
Although Git provides a git mv subcommand, it does not actually track name changes. Instead, it will assume that a name change occurred during a commit when one file disappeared, another appeared, and they have similar contents. Hence, even if the user uses git rm, a Unix command mv, and git add, Git will preserve the history for the file.
hg
Mercurial keeps track of the name a file had in each revision of a filelog. The hg rename subcommand must be used to preserve history.
move file
commit changes in staging area
In the case of Git, the staging area is the index.
In the case of Mercurial, the staging area is the files in the working directory which are tracked.
commit identifiers
mercurial:
null refers to an empty revision which is the parent of revision 0.
Branch and Merge
git
Git has a low level feature called a ref which it uses to implement branches and tags. A ref is a file in .git/refs which contains the hash of a commit. Branches are in .git/refs/heads and tags are in .git/refs/tags. Whenever a commit is made, the value in .git/refs/heads/BRANCH is updated where BRANCH is the current branch. The values in .git/refs/tags/TAG do not change.
The name of the branch which is currently checked out is stored in .git/HEAD. It is stored as the relative path refs/head/NAME.
Git also stores remote branches and tags in .git/refs/remotes/REPO. The git branch -r command can be used to list remote branches. Remote branches have names of the form REPO/BRANCH, and each remote branch will usually have a tracking branch, which is a local branch named BRANCH. This will be the case for any branches which were copied when a repository is created via git clone. A tracking branch can also be created when a remote repository is added using git remote -t BRANCH REPO URL. git fetch will only update remote branches. git pull will update remote branches and merge them with their tracking branches.
The default branch is called master. It is created by git init, and is the branch that is copied by git clone if no branch is explicitly specified.
Commits have zero or more parent commits. git commit creates a commit with one parent, except in the case of the initial commit. git merge creates a commit with two or more parent commits. If the commit has three or more parents, the merge is called an octopus merge.
staging numbers:
To perform a merge Git gets the tree contained in the common ancestor and puts its items into the staging area with staging number 1. It puts the current branch tree items in the staging area with staging number 2. It puts the tree items of the other branches in the staging area with staging number 3 or higher.
fast-forward commits aren't actually commits:
Suppose that bar is a branch of foo. If commits have subsequently been made to foo but not to bar, then running the following when bar is the current branch will perform a fast-forward:
git merge foo
In a fast-forward no merge commit is created. Instead the head of bar is simply moved to point to the same commit as the head of foo.
hg
A Mercurial branch is a name which is stored in a changeset. When a commit is made, the new changeset inherits the branch name of the previous changeset, unless a different name was specified before the commit with hg branch. To switch to a new branch one must make a commit.
Mercurial branches differ from Git branches in that:
- every commit belongs to a single branch
- a branch can have multiple heads
Mercurial tags are names for changesets. They are stored in the .hgtags file at the repository root. Creating a tag requires making a commit.
Mercurial does not support octopus merges. Thus changesets have at most two parents. A changeset created by hg merge sets the branch of the new changeset to be the branch of the first argument.
Changesets can have no branch specified. This is also called the default branch.
bookmarks:
Mercurial bookmarks work like Git branches, with the exception that Mercurial does not have the equivalent of Git tracking branches.
list "dedicated commit" branches
"dedicated commit" branches is the term used in this sheet to distinguish Mercurial-style branches from Git-style branches. Mercurial bookmarks are equivalent to Git-style branches.
In Git, branches are names which contain the hash of a commit. This commit is the head of the branch, and because each commit knows its parents, the entire history of the branch can be constructed. Git commits can belong to multiple branches, or they can belong to none at all. If a Git commit is not reachable from any branch or tag, it is at risk of being garbage collected.
In Mercurial, each changeset has a branch name associated with it. Thus, each changeset must belong to exactly one branch. Also, Mercurial branches can have multiple tips, whereas a Git branch always has a single head.
Mercurial does not provide a mechanism for renaming or deleting branches. The recommended way to get rid of unwanted branches is to rename the repository and then clone it to the original name with:
$ hg clone -r REV
History
Push and Pull
git
The basic command for getting changes from a remote repository origin is:
$ git fetch
Which branches are fetched is controlled by the fetch key in the remote section of .git/config. If the local repository was created by git clone, here is a likely value:
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
In this case, git fetch origin connects to the remote repository and copies all of the remote branches to refs/remotes/origin. Then it adds all remote objects referred to by the remote branches to the local objects database. It also puts the remote HEAD into FETCH_HEAD. The + indicates that local branches should be updated even if the commits are not fast-forwards.
The basic command for sending changes back to the remote repository origin is:
$ git push
Which branches are pushed is controlled by the push key in the remote section of .git/config. Here is an example entry which pushes commits on the master branch, and fails if the commits are not fast-forwards:
[remote "origin"]
push = refs/heads/master:refs/heads/master
A git pull is a git fetch followed by a git merge FETCH_HEAD, which git fetch sets to whatever was in HEAD on the remote repository.
hg
hg pull pulls changesets for all the remote branches that are also local branches unless branches are listed explicitly with the -b flag. hg pull -u is equivalent to hg pull followed by hg update. Pulling can create local branches with multiple heads, in which case an hg update will fail. An hg merge is used to merge the two heads, or an hg commit --close-branch is used to mark one of them as closed.
hg push pushes changsets for all local branches that are also remote branches unless branches are listed explicitly with the -b flag. A push which would create a branch with multiple heads will fail unless the -f flag is used. The --new-branch flag must be used to create a new branch.
Configuration Files
External Repositories
Packaging
Integrity Check and Garbage Collection
integrity check
garbage collection
Version Control
| distributed | client-server | local | |||
|---|---|---|---|---|---|
| $ git CMD | $ hg CMD | $ svn CMD | $ cvs CMD | $ rcs CMD | |
| online documentation | help | help | help | $ man cvs | $ man rcs |
| repository | |||||
| create new repository | init | init | init | $ mkdir RCS | |
| get local copy of repository from server or existing repository | clone | clone | checkout/co | checkout/co | |
| show remote repositories | remote -v show | paths | |||
| add remote repository | remote add | ||||
| working directory | |||||
| update working directory to most recent version of a branch | checkout | update/up | update/up | update | co |
| lock a file | lock | co -l | |||
| unlock a file | unlock | co -u | |||
| make working directory match the most recent commit | reset | revert | revert | ||
| show files in working directory which don't match the most recent commit | status | status/st | status/st | status | |
| show difference between file in working directory and most recent commit | diff | diff | diff/di | diff | diff |
| store uncommitted working directory changes in a temporary location | stash | shelve | |||
| tracking and committing | |||||
| put file under version control | add | add | add | add | ci -i |
| change name of a file under version control | mv | rename/mv | move/mv | ||
| mark file as not present in the next commit | rm | remove/rm | delete/rm | remove | |
| create new commit | commit | commit/ci | commit/ci | commit/ci | ci |
| create commit which undoes the result of a previous commit | revert | backout | |||
| branching and merging | |||||
| create branch | branch | branch(es) | copy/cp | tag -b | ci -r |
| merge branches | merge | merge | merge | ||
| move commits on a branch to the end of another branch | rebase | rebase | |||
| mark file with merge conflicts as resolved | add | resolve | resolve | ||
| history | |||||
| annotate lines of source code with commit info | blame | annotate | blame/ann | annotate | |
| show commit information for current branch in reverse chronological order | log | log -b tip | log | log | log |
| show difference between two commits | diff | diff | diff -rREV1 -rREV2 | ||
| find commit which introduced a change | log -S | grep | |||
| write contents of a file version to standard out | show | cat | cat | checkout -p | co |
| give name to a commit | tag | tag(s) | copy/cp | tag | $ rcs -nTAG:REV |
| pulling and pushing | |||||
| show commits available to be pulled or update tracking branches | fetch | incoming/in | |||
| get commits from a remote repository | pull | pull | |||
| push commits to a remote repository | push | push | |||
| configuration | |||||
| add user information | config | ||||
| ___________________________________________________ | __________________________ | __________________________ | __________________________ | __________________________ | __________________________ |
sccs (1972)
- CSSC Documentation CSSC is the GNU implementation of SCCS
- The Source Code Control System Rochkind 1975
In his 1975 paper Rochkind describes SCCS as a "radical departure from conventional methods for controlling source code". SCCS was initially implemented in 1972 on the IBM 370. The implementation language was SNOBOL. Rochkind was an employee of Bell Laboratories and SCCS was soon ported to Unix where it became a cornerstone of the "Programmer's Workbench", a suite of software distributed with early Unix.
The radical departure of SCCS appears to be the decision to store every version of each file under source control. This is done in a space efficient manner by means of deltas: the original file is stored with a delta for each change. To get the most recent version of the file all of the deltas must be applied to the original file. Also stored with each delta is the name of the user who made the change, the date and time of the change, and a user supplied comment explaining the change.
SCCS introduces a file format so that the original file, the deltas, and the meta-information can all be stored in a single history file. If the original file was foo.c, a common early convention was for the history file to be named s.foo.c. In the original Unix implementation the SCCS commands were standalone Unix commands. Starting with the version of SCCS which Allman wrote for BSD Unix in 1980 the SCCS commands became arguments or subcommands to a sccs executable.
Here is an sample SCCS session. The file foo.txt is put under source control. It is then checked out, edited, and the change committed. Finally a non-editable copy of the most recent version is checked out.
$ echo "foo" > foo.txt
$ sccs admin -ifoo.txt s.foo.txt
$ rm foo.txt
$ sccs get -e s.foo.txt
$ vi foo.txt
$ sccs delta s.foo.txt
$ sccs sccsdiff -r1.1 -r1.2 s.foo.txt
$ sccs get -p s.foo.txt > foo.txt
The SCCS history file format consists of fields separated by the Ctrl-A (ASCII 1) characters. The fields are divided into headers, which contain the meta-information, and the body, which contains the original file and the deltas. The original file is given revision number 1, and the number is incremented with each change.
The body consists of the original file interspersed with nested insert blocks and delete blocks. The format for an insert block is
^AI REV
added line one
added line two
...
^AE REV
where REV is the revision number for which the lines were added. Similarly the format for a delete block is
^AD REV
deleted line one
deleted line two
...
^AE REV
When extracting a version of the file, the desired version is compared with each block. Insert blocks are ignored if they have a higher number than the desired version and delete blocks are ignored if they have a lower or equal number than the desired version.
rcs (1982)
In RCS, the history file is always identified with a ,v suffix; the history file for foo.txt is foo.txt,v. Because this convention is used consistently, RCS commands can take the original file as an argument instead of the history file like in SCCS.
One can keep the ,v files in a separate directory. RCS has built in support for using a subdirectory named RCS in the same directory as the source. When this convention is used, it is not necessary to specify both the ,v file and the source file when using rcs ci and rcs co. If the source code tree has subdirectories, each subdirectory should contain an RCS subdirectory.
RCS supports multiline commit messages and it adds the log command for getting all the commit messages for a file.
example session
Here is an example work session using RCS. It is equivalent to the SCCS work session in the previous section.
$ echo "foo" > foo.txt
$ rcs ci -i foo.txt
$ rcs co -l foo.txt
$ vi foo.txt
$ rcs ci foo.txt
$ rcs co foo.txt
make has a built-in rule for creating a file from its ,v file. The file will be checked out as read-only.
rcs file format
- man rcsfile The RCS history file format
An RCS history file has four sections:
- head
- deltas
- description
- deltatexts
The head contains the revision number of the current version. If any of the revision numbers have been assigned symbolic names (i.e tags), they are listed here. If there
There is a delta section for each revision. It contains the time the revision was added to the history file and the author.
The description is a string describing the file. Strings are delimited by ampersands @. An ampersand in the string is escaped by doubling it.
There is a deltatext section for each revision. It contains a log, which is the commit message, and the text), which is either the full text of the revision or an ed style edit describing how to generate the revision from another revision. Both the log and the text are ampersand delimited strings with ampersands escaped by doubling.
Here is an example of a text which adds two lines after line 6:
@a6 2
added line one
added line two
@
Here is an example o a text which deletes two lines after line 6:
@d6 2
@
revision numbers and branching
RCS revision numbers consist of 2n positive integers joined by decimals. n is itself positive. By default the revision number given to a file when it is first placed under version control is 1.1.
RCS revision numbers with 2 integers refer to revisions on the trunk. RCS revision numbers with 4 integers refer to branches off the trunk. The first two integers indicate the trunk revision that is the root of the branch. RCS revision numbers with 6 integers refer to branches off of a branch of the trunk.
When a commit is made, by default the last integer of the revision is incremented.
When a branch is created off of a revision that does not have a branch, the revision number of the new revision is created from the revision number of the root of the branch by appending .1.1 to it. If the root revision already has a branch off of it, the new branch revision number will have a .2.1 appended to it.
cvs (1990)
CVS uses RCS to manage the history of each file under version control.
How to set up a CVS repository:
$ mkdir cvsroot
$ export CVSROOT=/PATH/TO/cvsroot
$ cvs init
For CVS commands to work, either the CVSROOT environment variable must be set or the location of the repository root must be passed to the command with each invocation using the -d option.
It is possible to set up a server on the repository host which listens on port 2041. The server uses ssh authentication, so the client must have an account on the host. To use the server, the client sets the CVSROOT environment variable to something like this:
$ export CVSROOT=:pserver:foo.com:/PATH/TO/cvsroot
How to create a project in the repository:
$ mkdir foo
$ cd foo
$ touch README
$ cvs import foo FOO_CORP V1
The 2nd and 3rd argument to cvs import are required and are used to create tags.
Here is an example of how to check out the foo project but name the working directory bar:
$ cvs checkout -d bar foo
Files only needed to only needed to be added once, like Mercurial and unlike Git:
$ cd bar
$ vim Makefile
$ cvs status
$ cvs diff
$ cvs add Makefile
$ cvs commit -m 'adding a Makefile'
$ cvs log
Branching is a three step process: (1) tag the commit you are branching from, (2) create the branch, and (3) update the working directory to the branch.
$ cvs tag WUMPUS_ROOT
$ cvs tag -r WUMPUS_ROOT -b WUMPUS
$ cvs update -r WUMPUS
How to merge
svn (2000)
How to set up an SVN server:
$ svnadmin create /PATH/TO/svn
$ vim /PATH/TO/svn/conf/svnserve.conf
$ vim /PATH/TO/svn/conf/passwd
$ mkdir /tmp/empty
$ svn import /tmp/empty file:///PATH/TO/svn/NAME
$ svnserve -d -r /PATH/TO/svn --log-file /PATH/TO/svn/svnserve.log
$ svn co svn://localhost/NAME
When editing svn/conf/svnserve.conf, add these lines to the [general] section:
anon-access = none
auth-access = write
password-db = passwd
In svn/conf/passwd, create a username and password:
joe = passwerd123
To have svnserver start automatically at boot on an Ubuntu server, put this script in /etc/init.d. Change the value of DAEMON_ARGS from -d -r /usr/local/svn/repos to -d -r /PATH/TO/svn —log-file /PATH/TO/svnserve.log.
Archive and Patch Tools
diff | cpio | diff3 | ar | tar | patch | zip | diffstat | jar | rsync | colordiff
diff (1974)
- An Algorithm for Differential File Comparison Hunt & McIlroy 1976
- man diff
To implement an efficient version control system one needs to find a minimal delta or difference between two similar text files. The problem led to the development of the Unix diff utility. Regarding a file as a sequence of lines, the problem can be treated as an example of the longest common subsequence problem. The standard solution to this problem has O(nm) performance in both time and space, where n and m are the lengths of the two files. To facilitate quick comparison of lines, each line is replaced with a hash code. When implementing diff McIlroy developed an algorithm that was more efficient than the standard solution in most cases.
The standard diff notation prefixes lines with < and > to indicate whether the line originated in the first or second file. It also uses the letters a, c, and d to indicate lines being added, changed, or deleted:
$ echo "foo" > foo.txt
$ echo "bar" > bar.txt
$ diff foo.txt bar.txt
1c1
< foo
---
> bar
$ diff foo.txt /dev/null
1d0
< foo
$ diff /dev/null foo.txt
0a1
> foo
These letters used in diff notation are also ed commands. In fact, diff -e will output an ed script which can be used to convert the first file into the second:
$ diff -e foo.txt bar.txt > diff.ed
$ ( cat diff.ed ; echo "w" ) | ed foo.txt
The version of diff released with BSD 2.8 in 1981 added the -c option to show three lines of context around each change. This is called the context format.
The BSD 2.8 diff also added an -r option to perform a recursive diff on directories.
In 1990 the -u option was added, which gives a diff inunified format. In the context format, if a line is changed, the context is repeated: once around the old version of the line and once around the new. The uniformed format puts both version of the line in the same context, reducing the size of the diff file.
The -C NUM and -U NUM options are like the -c} and {{-u options, except that they show NUM lines of context.
normal format:
$ sed s/^root:/ROOT:/ /etc/passwd > /tmp/passwd
$ diff /etc/passwd /tmp/passwd
12c12
< root:*:0:0:System Administrator:/var/root:/bin/sh
---
> ROOT:*:0:0:System Administrator:/var/root:/bin/sh
ed script format:
$ sed s/^root:/ROOT:/ /etc/passwd > /tmp/passwd
$ diff -e /etc/passwd /tmp/passwd
12c
ROOT:*:0:0:System Administrator:/var/root:/bin/sh
.
context format:
$ sed s/^root:/ROOT:/ /etc/passwd > /tmp/passwd
$ diff -c /etc/passwd /tmp/passwd
*** /etc/passwd 2013-10-24 17:38:39.000000000 -0700
--- /tmp/passwd 2014-04-26 12:57:57.000000000 -0700
***************
*** 9,15 ****
# Open Directory.
##
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
! root:*:0:0:System Administrator:/var/root:/bin/sh
daemon:*:1:1:System Services:/var/root:/usr/bin/false
_uucp:*:4:4:Unix to Unix Copy Protocol:/var/spool/uucp:/usr/sbin/uucico
_taskgated:*:13:13:Task Gate Daemon:/var/empty:/usr/bin/false
--- 9,15 ----
# Open Directory.
##
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
! ROOT:*:0:0:System Administrator:/var/root:/bin/sh
daemon:*:1:1:System Services:/var/root:/usr/bin/false
_uucp:*:4:4:Unix to Unix Copy Protocol:/var/spool/uucp:/usr/sbin/uucico
_taskgated:*:13:13:Task Gate Daemon:/var/empty:/usr/bin/false
unified format:
$ sed s/^root:/ROOT:/ /etc/passwd > /tmp/passwd
$ diff -u /etc/passwd /tmp/passwd
--- /etc/passwd 2013-10-24 17:38:39.000000000 -0700
+++ /tmp/passwd 2014-04-26 12:57:57.000000000 -0700
@@ -9,7 +9,7 @@
# Open Directory.
##
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
-root:*:0:0:System Administrator:/var/root:/bin/sh
+ROOT:*:0:0:System Administrator:/var/root:/bin/sh
daemon:*:1:1:System Services:/var/root:/usr/bin/false
_uucp:*:4:4:Unix to Unix Copy Protocol:/var/spool/uucp:/usr/sbin/uucico
_taskgated:*:13:13:Task Gate Daemon:/var/empty:/usr/bin/false
recursive format:
$ mkdir /tmp/a /tmp/b
$ cp /etc/passwd /tmp/a
$ $ sed s/^root:/ROOT:/ /etc/passwd > /tmp/b/passwd
$ diff -r /tmp/a /tmp/b
diff -r /tmp/a/passwd /tmp/b/passwd
12c12
< root:*:0:0:System Administrator:/var/root:/bin/sh
---
> ROOT:*:0:0:System Administrator:/var/root:/bin/sh
cpio (1977)
An ancient and to most people unfamiliar Unix archiving tool which is roughly equivalent to tar. The suffix .cpio is often used for cpio archive files.
The format is used by RPM packages, though RPM 5.0 and later also support the xar format. The Linux kernel since version 2.6 has a cpio archive called initramfs which it uses during the boot process. cpio is also used by the Mac OS X .pkg format.
The cpio file format is similar to the tar file format in that for each file which is added to an archive, a header and the file contents are appended to the archive file. In the case of cpio the header is smaller (76 bytes vs 512 bytes). This is in part because the header only contains the file name length; the actual file name is appended to the archive file between the header and the file contents. By contrast the tar format stores the name in fixed length fields, putting a limit on the possible path length. Another different is the cpio format lacks a checksum.
| header format | |||
|---|---|---|---|
| offset | length | field | description |
| 0 | 6 | c_magic | The identifying value "070707" |
| 6 | 6 | c_dev | |
| 12 | 6 | c_ino | c_dev and c_ino together must be unique for each file in the archive |
| 18 | 6 | c_mode | |
| 24 | 6 | c_uid | |
| 30 | 6 | c_gid | |
| 36 | 6 | c_nlink | number of links to the file in the archive; can be incorrect if the -a flag was used to append files |
| 42 | 6 | c_rdev | a place for implementations to store character or block special file information |
| 48 | 11 | c_mtime | |
| 59 | 6 | c_namesize | |
| 65 | 11 | c_filesize |
Another difference between tar and cpio is that whereas tar takes the files to be archived on the command line, recursively descending any arguments which are directories, cpio when used with the -o flag takes its list of files to be archived from standard input. cpio was designed to be used with the find command. Similarly when using the i flag cpio reads the files to be extracted from an archive from standard input.
diff3 (1979)
diff3 displays the differences between three versions of the same file.
The three way diff is the foundation of branch merging. A two way diff is insufficient for merging because deleting a line in one branch looks like adding a line in the other branch. Only by comparing both branches with the original can these two cases be distinguished.
diff3 has three basic invocations:
diff3 EDIT1 ORIG EDIT2
diff3 -e EDIT1 ORIG EDIT2
diff3 -m EDIT1 ORIG EDIT2
The first invocation writes a description of the three-way diff to standard out.
The second invocation writes an ed script to standard out which will merge the changes in EDIT2 to EDIT1.
The third invocation performs the merge. It writes a version of the file with changes from both EDIT1 and EDIT2 to standard out.
Here is an example of the output format used by the first invocation:
$ cat /tmp/orig.txt
a
b
c
d
e
$ cat /tmp/edit1.txt
a
b1
c
d
e
f
$ cat /tmp/edit2.txt
a
b
c
d1
e
$ diff3 /tmp/edit1.txt /tmp/orig.txt /tmp/edit2.txt
====1
1:2c
b1
2:2c
3:2c
b
====3
1:4c
2:4c
d
3:4c
d1
====1
1:6c
f
2:5a
3:5a
Each hunk of the diff3 output starts with four hyphens. All of the hunks in the example above are two-way hunks, meaning that two of the three files are the same. In this case the number of the differing file as it appears in the diff3 arguments is placed after the hyphens.
Here is an example of a three-way hunk, where all three files differ and no number is placed after the hyphens:
$ cat /tmp/orig.txt
a
$ cat /tmp/edit1.txt
a1
$ cat /tmp/edit2.txt
a2
$ diff3 /tmp/edit1.txt /tmp/orig.txt /tmp/edit2.txt
====
1:1c
a1
2:1c
a
3:1c
a2
ar (1979)
A tool on Unix systems to create static libraries from compiled objects. In other words, to create a .a file from a set of .o files. The format is understood by the linker—which these days is usually built into the compiler—and the loader ld.
The command line interface is broadly similar to tar. Here is how to create an archive; remove files from an archive; list the archive contents; extract files from an archive:
ar -c NAME.a FILE ...
ar -d ARCHIVE FILE ...
ar -t ARCHIVE
ar -x ARCHIVE FILE ...
The ar file format is not standardized and may differ between systems.
The file format used by GNU ar on Linux starts with the new line terminated string "!<arch>".
Each file starts with a 60 bytes header, followed by the file contents. The header has the following fixed-width fields:
| offfset | length | name |
|---|---|---|
| 0 | 16 | file name in ASCII |
| 16 | 12 | file modification timestamp |
| 28 | 6 | uid |
| 34 | 6 | gid |
| 40 | 8 | file mode |
| 48 | 10 | file size in bytes |
| 58 | 2 | 0x60 0x0A |
The space allocated for the file name in the header is quite short. GNU ar actually stores a special file named "//" in the archive with a new line separated list of file names. A header can reference a name in this special file by storing "/" and a the decimal offset in the "//" file of the file name. When file names are stored directly in the header, a "/" is used to mark the end of the file and the rest of the field is space padded. This supports spaces in the file name.
GNU ar also stores a special file named "/" is the archive for a symbol table. The format is
- a 32-bit integer containing the number of symbols
- a list of 32-bit integers, one for each symbol, containing the offset of the header in the archive for the file containing the symbol
- a list of null terminated strings, in the same order as the previous list, containing the symbol names
tar (1979)
The more portable twin of ar. Originally used for creating and using magnetic tape archives.
How to create a tar file; list the contents of a tar file; compare a tar file with the file system; and extract the contents of a tar file:
tar [-]cf NAME.tar DIR
tar [-]tf TARFILE
tar [-]df TARFILE [DIR]
tar [-]xf TARFILE
The -v option can be used with -c or -x to write the files being added or extracted to standard error.
Tar files store the files in sequential order. Each file is precede by a 512 byte header. The file itself is null byte padded to a multiple of 512 bytes.
Tar can write to and read from stdout. The following two invocations behave identically:
tar cf - . | (cd DIR ; tar xf -)
tar cf . - | tar xf - -C DIR
Tar can append data to an existing tar file. These commands append the contents of a directory to a tar file; append the contents of the directory which are newer than what is already on a tarfile; append subsequent tar files to the first tar file:
tar [-]rf TARFILE DIR
tar [-]uf TARFILE DIR
tar [-]Af TARFILE1 TARFILE2 ...
How to create a compressed tar file:
tar [-]czf NAME.tar.gz
tar [-]cjf NAME.tar.bz2
tar [-]cJf NAME.tar.xz
In 1988 POSIX extended the format of the header block in a backwardly compatible way. Additional header type flags were added in 2001.
| header format | |||
|---|---|---|---|
| offset | length | original format | ustar |
| 0 | 100 | file name | |
| 100 | 8 | file mode | |
| 108 | 8 | owner user id | |
| 116 | 8 | group id | |
| 124 | 12 | file size in bytes | |
| 136 | 12 | last modification time | |
| 148 | 8 | header checksum | |
| 156 | 1 | type flag | |
| 157 | 100 | name of linked file | |
| 257 | 6 | "ustar" | |
| 263 | 2 | "00" | |
| 265 | 32 | owner user name | |
| 297 | 32 | group name | |
| 329 | 8 | device major number | |
| 337 | 8 | device minor number | |
| 345 | 155 | filename prefix |
| header type flags | |||
|---|---|---|---|
| flag | original meaning | ustar | 2001 |
| '\0' | normal file | ||
| '0' | normal file | ||
| '1' | hard line | ||
| '2' | symlink | ||
| '3' | character device | ||
| '4' | block device | ||
| '5' | directory | ||
| '6' | FIFO | ||
| '7' | contiguous file | ||
| 'g' | global extended header | ||
| 'x' | extended header for the next file |
patch (1985)
The patch command can apply the output of diff to the file that was the first argument of diff to recover the file that was the second argument of diff. patch reads the output of diff from standard input:
$ echo "foo" > foo.txt
$ echo "bar" > bar.txt
$ diff foo.txt bar.txt > foo.patch
$ patch foo.txt < foo.patch
patching file foo.txt
$ cat foo.txt
bar
The above is only a slight improvement over what could have been achieved with diff -e and ed. The novelty of patch is its ability to apply a patch file to an entire directory:
$ mkdir old
$ echo "bar" > old/bar.txt
$ echo "baz" > old/baz.txt
$ cp -R old new
$ echo "qux" > new/bar.txt
$ diff -Naur old new > foo.patch
$ rm -rf fnew
$ patch -Np0 < foo.patch
patching file old/bar.txt
$ cat old/bar.txt
qux
This is a good way to create a patch file:
diff -Naur OLD NEW
When creating the patch file with diff, the -u or -c flags seem to be necessary so that patch has the file names. The -N flag is necessary if files are added or removed. The -a flag prevents diff from skipping files which it thinks are binary.
If the diff was performed outside of the directories, then the patch should be performed outside of the directory to be patched with the -p0 flag. Optionally the patch can be performed inside the directory to be patched with the -p1 flag. The -N flag instructs patch to not make a change if the patch appears to be reversed or already applied.
zip (1989)
zip combines file compression and archiving. It is a better choice for sharing files with Windows hosts than tar, which most Windows hosts don't have installed.
zip [-r] [-0] ARCHIVE FILE ...
zip -d ARCHIVE FILE ...
zip -u ARCHIVE [FILE ...]
unzip -l ARCHIVE
unzip ARCHIVE [FILE ...]
Compression is the DEFLATE algorithm, or no compression if the -0 flag is used.
zip stores the file name, file size, and last modification time of the file. The information is in a header which precedes the file itself and in the "central directory" at the end of the file.
By default zip does not recursively descend directories, adding their contents to the archive. Use the -r flag to get this behavior.
diffstat (1992)
Summarizes a recursive diff on two directories. It lists the files that were modified, added, or deleted with the number of lines which changed.
jar (1995)
jar supports some of the tar commands:
jar cf NAME.jar DIR
jar tf JARFILE
jar xf JARFILE
jar uf JARFILE DIR
jar can write to and read from stdout; the syntax is different from tar:
jar c . | (cd DIR ; jar x)
jar c . | jar x -C DIR
Use jar -e to make a jar file runnable by java. The argument to -e is a class with a main routine which will be used as the entry point.
$ mkdir
$ cat > foo/A.java
package foo;
public class A {
public static void main(String[] args) {
System.out.println("A");
}
}
$ sed s/A/B/ foo/A.java > foo/B.java
$ javac foo/*.java
$ jar cef foo.A foo.jar foo
$ java -jar foo.jar
A
A jar file is a zip file; unzip can also be used to extract the contents. jar stores extra information about the jar file in META-INF/MANIFEST.MF:
$ unzip foo.jar
$ cat META-INF/MANIFEST.MF
Manifest-Version: 1.0
Created-By: 1.6.0_26 (Sun Microsystems Inc.)
Main-Class: foo.A
rsync (1996)
A tool for copying files and directories between hosts. Usually it uses ssh. It is faster than scp when some of the files are already on the destination or when copying files that have been modified.
Here is the usage for putting and getting:
rysnc -a PATH ... HOST:PATH
rsync -a HOST:'PATH ...' PATH
The -a flag is equivalent to the flags -rptoglD which (1) recursively copy the contents of directories, (2) copy file permissions, (3) copy file times, (4) copy owner, (5) copy group, (6) copy symlinks, and (7) copy special devices.
Other useful flags are -v for verbose mode and --exclude which takes a file glob pattern to specify files to skip.
If the source and target paths have the same basename, then rsync will copy the contents of the source into the contents of the target. If the basenames are different, rsync will create a directory with the same name as the source inside the target. This behavior can be suppressed by putting a trailing slash / on the end of the source.
rsync can be used to backup a directory on a remote host. With the --backup flag, files which are already on the destination but have been modified on the source will be copied into a separate incremental directory with a tilde (~) suffix. The --backup-dir flag can be used to specify a different incremental directory.
colordiff (2002)
A version of diff which colorizes the output. It takes the same options as diff.


Speech
The Secretary of State for Education, Michael Gove, addresses the National College’s Annual Conference in Birmingham.
Thank you Tony for that kind introduction.
And thank you all, for the work that you do.
The service you give, the leadership you show, the example you set - they are all inspiring.
And they are what make my work worthwhile.
The wonderful thing about my job is the opportunity it gives me to see the very best of this country - young people achieving more than they ever thought they could, finding their special talent, taking charge of their own destinies, becoming authors of their own life stories.
Seeing the work you do - often against the odds, in difficult circumstances, with tight resources and challenging intakes - reaffirms one of my deepest convictions - there is no way to spend your life which is more admirable than following the vocation which inspires all of you - the calling to teach.
And there is no way I can do this job without listening to you as you explain what drives you, what your ambitions are for the children and young people in your care and what Government can do to serve you.
Which is why I was so glad to hear what Steve had to say - because the political leadership I want to provide is all about service. It should be Government’s job to help, serve and support you - not direct, patronise and fetter you.
I believe that heads and teachers are the best people to run schools - not politicians or bureaucrats.
The people from whom I have learnt the most while in politics have been headteachers - people like Fiona Hammans at Banbury School, Joan McVittie at Woodside High, Mike Wilshaw at Mossbourne Community Academy, Mike Griffiths at Northampton School for Boys, Mike Spinks at Urmston Grammar, Sue John at Lampton School, Patricia Sowter at Cuckoo Hall, Sally Coates at Burlington Danes, and so many more.
At the heart of this Government’s vision for education is a determination to give school leaders more power and control. Not just to drive improvement in their own schools - but to drive improvement across our whole education system.
Looking back over the last 15 years there are any number of things I could criticise - but I won’t - instead I want to celebrate the gains which have been made - and one of the most important is the development and deepening of culture in which we recognise that it is professionals, not bureaucratic strategies and initiatives, which drive school improvement.
Teachers grow as professionals by allowing their work to be observed by other professionals, and observing the very best in their field, in turn.
Headteachers improve their schools fastest and most effectively by working with other heads who have been on that journey. And both sides gain from the collaboration. Mentoring others is often the best form of professional development.
The whole culture of the National College under Steve has been informed by this vision of system-led leadership that taps into the profound moral purpose of the profession, which is why I am so grateful to him - and especially admiring of what has been achieved by all of you who are National Leaders of Education.
But admiring as I am of what has been achieved I am, frankly, impatient for us all, as a nation, to do better.
Harold Wilson once said of the Labour Party, it is a moral crusade or it is nothing. Well, whatever view one takes of the Labour Party’s history, I believe that we have to ensure there is a driving, crusading, vision at the heart of our Government’s education policy. Or we will forfeit our mandate.
Unless we are guided by moral purpose in this coalition government then we will squander the goodwill the British people have, so generously, shown us.
And the ethical imperative of our education policy is quite simple - we have to make opportunity more equal.
We have to overcome the deep, historically entrenched, factors which keep so many in poverty, which deprive so many of the chance to shape their own destiny, which have made us the sick man of Europe when it comes to social mobility.
It is a unique sadness of our times that we have one of the most stratified and segregated school systems in the developed world.
We know, from Leon Feinstein’s work, that low ability children from rich families overtake high ability children from poor families during primary school.
And the gap grows as the children get older. A child eligible to free school meals is half as likely to achieve five or more GSCEs at grade A*-C, including English and maths, than a child from a wealthier background.
By 18 the gap is vast. In the most recent year for which we have data, out of 80,000 young people eligible for free school meals, just 45 made it to Oxbridge. That’s fewer than some private schools manage by themselves.
We are clearly, as a nation, still wasting talent on a scale which is scandalous. It is a moral failure, an affront against social justice which we have to put right.
And that is why I am so glad that at the heart of our Coalition’s programme for Government is a commitment to spending more on the education of the poorest. The pupil premium - supported by Conservatives but championed with special passion and developed in detail by our Liberal Democrat partners - is a policy designed to address disadvantage at root. By giving resources to the people who matter most in extending opportunity - school leaders and teachers.
And far from difficult economic times being a reason to scale down our ambitions, the economic challenges we face are only reason to accelerate our reform programme.
Because the days are long gone - if they ever existed - when we could afford to educate a minority of our children well while hoping the rest were being schooled adequately.
Already China and India are turning out more engineers, more computer scientists and more university graduates than the whole of Europe and America combined.
And the success of other nations in harnessing their intellectual capital is a function of their determination to develop world-beating education systems. Across the globe other nations are outpacing us - pulling ahead in international comparisons, driving innovation, changing their systems to give professionals more freedom to grow, adapt, improve and learn from each other…
It is no longer enough, if it ever was, to say we as a nation are doing better than we did in the past. As Matt Ridley’s wonderful new book Rational Optimism shows, in almost every field of human endeavour we are doing exponentially better than we did in the past. The real test is how are we doing compared to the rest. And in particular, how are we doing compared to the best…
We have to ask ourselves how our 16-year-olds are doing relative to 16-year olds in Scandinavia, Singapore, Canada and Australasia.
Unless we learn from those nations which are innovating most imaginatively and successfully then we will be failing in our duty to the young people who are in our care while we hold office.
And the pace of change across the globe is accelerating. Many of those nations which are now the world’s strongest performers, from Finland to South Korea, were well behind us in levels of educational achievement a generation ago. Now they put us to shame.
Twenty years ago we were 14th in the world when nations were measured on how well they educated their teenagers. Now we are 23rd.
In English, Maths and Science, the figures from the most respected international comparisons also show us falling behind other nations.
For the fourth-largest economy in the world, with a much higher than average level of investment in education and some of the most talented professionals anywhere in the globe, this performance simply isn’t good enough.
But while the comparisons are sobering, the reasons to be optimistic are plentiful. Indeed most of them are in this room.
If you look at the most successful education systems in the world - those with the best absolute performance - and those with the highest levels of equity across classes - they all tend to have certain common features.
They extend a high level of autonomy to individual schools.
School leaders are empowered to innovate in their own schools
And they are expected to lead the drive for improvement in other schools.
The political leadership is uncompromising in the drive for higher standards.
There is a culture of high expectations which does not allow excuses to be made for poor performance on the basis of class, ethnicity or background.
There is a proper national framework of accountability.
Which includes the transparent publication of academic performance on a school-by-school basis with proper, externally set and marked, testing
And an inspection regime which is very light touch for high performing institutions so the real focus can be on under-performance.
Teaching is a high status profession which draws its recruits from among the highest performing graduates.
There is a strong culture of professional development which encourages teachers to improve their craft by learning from others while also deepening their academic knowledge.
All of these features - which characterise the best education systems in the world - are present in England. But not to the degree we require to keep pace with the world’s best.
Indeed, over the last three years I fear Government action has held our education system back from making many of the advances we needed to make to keep pace with the best.
Ministers decreased school autonomy, tried to drive improvement through bureaucratic compliance, complicated the inspection regime and simultaneously weakened and complicated our system of accountability.
The prospect of radical reform along the lines of the world’s best education systems, envisaged in the 2005 Education White Paper, was never fulfilled.
And while we rowed back on reform, the pace of change in other nations accelerated.
In America, President Obama is pressing ahead with radical school reform to close the gap between rich and poor. He has offered extra support to programmes designed to attract more great people into teaching and leadership, as well as encouraging states to provide greater accountability to parents and welcome new providers into state education.
He has insisted - along with other Democrat reformers like Arne Duncan, Joel Klein and Michelle Rhee - that there be more great Charter schools - the equivalent of our Academies - to drive up attainment, especially among the poorest. In New York, Charter schools - like the inspirational Knowledge is Power Programme schools - have dramatically narrowed the vast performance gap between black and white children and 91 per cent of those benefiting are on free or reduced price meals.
With a relentless focus on traditional subjects, a culture of no excuses, tough discipline, personalised pastoral care and enthusiastic staff who work free from Government bureaucracy to help every child succeed, these schools are amazing engines of social mobility that are now sending children from ghetto areas to elite universities.
In Canada, and specifically in Alberta, schools have also been liberated, given the autonomy enjoyed by charter schools in the US. Head teachers control their own budgets, set their own ethos and shape their own environments.
In Calgary and Edmonton, a diverse range of autonomous schools offer professionals freedom and parents choice.
And the result?
Alberta now has the best performing state schools of any English-speaking regions.
In Sweden, the old bureaucratic monopoly that saw all state schools run by local government was ended and the system opened up to allow new, non-selective, state schools to be set up by a range of providers.
It has allowed greater diversity, increased parental choice and has seen results improve - with results improving fastest of all in the areas where schools exercised the greatest degree of autonomy and parents enjoyed the widest choice.
Finland is often deliberately contrasted with Sweden because of the supposed rigidity of its education system.
But by placing a premium on specialism, diversity and parental choice within that framework, they too are driving up standards.
In Singapore, again often held up as a model of regimented Prussian-style centralism, dramatic leaps in attainment have been secured by schools where principals are exercising a progressively greater degree of operational autonomy. The Government has deliberately encouraged greater diversity in the schools system and as the scope for innovation has grown, so Singapore’s competitive advantage over other nations has grown too.
It is these examples - and these lessons - that explains our philosophical approach to education perhaps better than anything.
The most important people in driving school improvement aren’t inspectors, advisers, school improvement partners or Ministers.
It is teachers and school leaders.
And that is why I am passionate about extending the freedoms denied to you by the last government.
One of the first things we have done is give professionals more scope to drive improvement by inviting all schools to consider applying for academy freedoms.
This is an addition to, rather than replacement of the existing academies programmes, We will continue to ensure that academies are used to drive faster and deeper improvements in deprived and disadvantaged areas.
But we will now also provide you with the kind of autonomy that has served schools in America, Canada, Sweden and Finland so well and allow all schools the freedom to develop their own curriculum and fully control their own budget and staffing.
Since I issued my invitation to schools three weeks ago, I have been overwhelmed by the response.
More than 1772 schools have enquired about academy freedoms.
870 outstanding schools - including 405 secondary schools and more than 400 outstanding primaries have contacted us - and will lead the way.
That’s 70 per cent of the outstanding secondary schools in the country and a significant cohort of outstanding primaries.
I know some have expressed concern that this offer of greater autonomy for schools will work against the collaborative model of school improvement that has grown up over the past fifteen or so years and which has done so much to tackle under-performance in those schools in the most challenging circumstances.
Let me be clear: I would not be going down this road if I thought it would in any way set back the process of school improvement, if would in any way undermine the progress we need to make in our weakest or most challenged schools or if it would in any way fracture the culture of collaboration which has driven school improvement over the last decade.
This policy is driven, like all our education policy, by our guiding moral purpose - the need to raise attainment for all children and close the gap between the richest and poorest.
I believe this policy will only work if it strengthens the bonds between schools and leads to a step-change in system-led leadership.
That is why I will expect of every school that acquires academy freedoms that it partners at least one other school to help drive improvement across the board.
That is why I envisage a bigger role for the National College and the programme of National Leaders of Education in brokering and providing support from great schools for those who need help to improve.
And that is why any school which acquires academy freedoms will continue to be governed by admissions rules which guarantee fair access to all, safeguards the inclusive character of comprehensive schools, ensures all schools take their fair share of pupils in need and prevents any school discriminating in any way against those pupils with special educational needs.
Within the safeguards provided by these assurances I believe innovation can flourish. New approaches to the curriculum, to assessment, to discipline and behaviour, to pastoral care, to careers guidance, to sport, the arts and music, new ways of gathering data on pupil performance, new ways of supporting teachers to improve their practice, new ways of tackling entrenched illiteracy and the tragic culture of low expectations which blights so many white working class communities.
And this culture of innovation, I believe, has the potential to benefit all our children.
Earlier this month, Mike Gibbons of the Richard Rose Federation, wrote an article for the TES which encapsulated my vision.
More autonomous schools, he wrote, had in the past been
‘…perceived as ‘educational lifeboats’ to allow highly capable and driven parents to leave the main system.’
But, he argued, that the move to greater autonomy could in fact move our schools system in the opposite direction. More autonomous schools could, should, and in my view will, be ‘tugboats adding extra pull to the drive to increase universal standards, not innovations dragging much-needed resources away from the fleet.’
He then concluded by saying that:
If we can develop schools to become crucibles of innovation on behalf of the whole system, working for the sake of all children as well as meeting the needs of parents who are seeking different provision, then the sum continues to be greater than the parts. And so every school, regardless of its status, works for itself and for the whole system.
Mike is himself another example of an inspirational school leader.
He is also, of course, spot on.
Whole system improvement, a comprehensive approach to driving up standards for every child, is what the coalition Government aims to deliver.
Central to that drive is structural reform of the kind I’ve laid out - professionals liberated to drive improvement across the system.
But the success of that model is not the only example of good practice here in England we want to spread more widely, it’s not the only lesson from abroad we want to implement more urgently here.
We also want to take urgent action to attract more great teachers into the classroom. We want to further enhance the prestige and esteem of the teaching profession and further improve teacher training and continuous professional development.
Look at the highest performing nations in any measure of educational achievement and they are always, but always, those with the most highly qualified teachers. Whether its Singapore, South Korea or Finland, as Sir Michael Barber has pointed out in his ground-breaking study for McKinsey nothing matters more in education that attracting the best people into teaching and making sure that every minute in the classroom is spent with children benefiting from the best possible instruction.
The generation of teachers currently in our schools is the best ever, but given the pace of international improvement we must always be striving to do better.
That is why we will expand organisations such as Teach First, Teaching Leaders and Future Leaders which have done so much to attract more highly talented people into education.
That is why we will write off the student loan payments of science and maths graduates who go into teaching.
That is why we will reform teacher recruitment to ensure there is a relentless focus on tempting the best into this, most rewarding, of careers.
And that is why we will reform teacher training to shift trainee teachers out of college and into the classroom.
We will end the arbitrary bureaucratic rule which limits how many teachers can be trained in schools, shift resources so that more heads can train teachers in their own schools, and make it easier for people to shift in mid-career into teaching.
Teaching is a craft and it is best learnt as an apprentice observing a master craftsman or woman. Watching others, and being rigorously observed yourself as you develop, is the best route to acquiring mastery in the classroom. Which is why I also intend to abolish those rules which limit the ability of school leaders to observe teachers at work. Nothing should get in the way of making sure we have the best possible cadre of professionals ready to inspire the next generation.
And that is why I will also reform the rules on discipline and behaviour to protect teachers from abuse, from false allegations, from disruption and violence. The biggest single barrier to good people starting, or staying, in education is poor pupil behaviour and we need a relentless focus on tackling this issue. That means getting parents to accept their responsibilities, giving teachers the discretion they need to get on with the job and sending a clear and consistent message at all times that adult authority has to be respected if every child is to have their chance.
As well as giving teachers more control over their classrooms I want to give them more control over their careers, developing a culture of professional development which sees more teachers acquiring postgraduate qualifications like masters and doctorates, more potential school leaders acquiring management qualifications and more support in place for those who want, quickly, to climb up the career ladder. In every single one of these areas the role of the National College will be crucial and I hope we can all work ever more closely together.
Investing in the workforce is one crucial lesson of great education systems, alongside granting your leaders greater autonomy. But there are others which we are also determined to push forward.
The best school systems generate rich quantities of data which enable us all to make meaningful comparisons, learn from the best, identify techniques which work and quickly abandon ideologies which don’t. In America, President Obama, the Gates Foundation, the top charter schools and the principal education reformers all recognise the need for richer, timelier, more in-depth data about performance.
That is why we need to keep rigorous external assessment. Improve and refine our tests, yes, but there can be no going back to the secret garden when public and professionals were in ignorance about where success had taken root and where investment had fallen on stony ground.
Indeed I want to see more data generated by the profession to show what works, clearer information about teaching techniques that get results, more rigorous, scientifically-robust research about pedagogies which succeed and proper independent evaluations of interventions which have run their course. We need more evidence-based policy making, and for that to work we need more evidence.
And that also means a new role for Ofsted. I want to see an inspection regime which also mirrors the approach of the world’s most successful systems. Intervention should be in inverse proportion to success. The best needed only the lightest touch to continue on a course of improvement. Those who are struggling need closer attention. That is why we will direct Ofsted’s resources to those schools which are faltering, or coasting, and insist that inspectors spend more time on classroom observation and assessing teaching and learning than having their attention diverted to other, strictly peripheral, areas.
There is one other area where I also want us to learn from abroad, indeed to compare ourselves as we have never done before. And that is with our curriculum and qualifications.
I want to ensure our national curriculum is a properly international curriculum - that it reflects the best collective wisdom we have about how children learn, what they should know and how quickly they can grow in knowledge.
I want to use the evidence from those jurisdictions with the best-structured and most successful curricula - from Massachusetts to the Pacific Rim - to inform our curriculum development here.
I want to remove everything unnecessary from a curriculum that has been bent out of shape by the weight of material dumped there for political purposes. I want to prune the curriculum of over-prescriptive notions of how to teach and how to timetable. Instead I want to arrive at a simple core, informed by the best international practice, which can act as a benchmark against which schools can measure themselves and parents ask meaningful and informed questions about progress.
And alongside curriculum reform informed by evidence I want exam reform sustained by evidence. I want to ensure our qualifications can stand comparison with the most stretching in the world. I want to ensure that the maths tests our 11-year-olds sit are comparable with those 11-year-olds in Singapore sit and the science qualifications 16 or 18-year-olds acquire here are directly comparable with those in Taiwan or Toronto. That is why I want Ofqual to work not just to guarantee exam standards over time, but to guarantee exam standards match the best in the world.
I won’t deny for a moment this is an ambitious agenda. But I don’t think there’s any point being in politics, fighting elections, seeking office unless you’re ambitious to make a difference.
And if there’s any audience I can confess to ambition in front of, it’s you. Every day your nurture it, encourage it, celebrate it. You’re ambitious for your schools, for the young people in your care, for the students they will become. You want them to be pushed, nudged, cajoled, encouraged, tempted and inspired to do more than they ever thought possible. And you want them to rejoice in knowing they have achieved their full potential.
And that is what I want too. In the relentless drive to help every child achieve everything of which they are capable there can be neither rest nor tranquillity. But there can be the endless satisfaction of seeing the human spirit ennobled and fulfilled. That is the task you have been called to lead. And it is my job to serve you.
Published: 25 November 2010


To find email addresses on LinkedIn, click on Email Hunter's button on profiles! If this button doesn't appear, please contact us at<EMAIL_ADDRESS>Hey! Are you satisfied by Email Hunter's Chrome extension?
Yes
No
Glad to hear this! Please help us rating it in Chrome Web Store :)
Add a rating
You've reached your daily limit! Please connect to your Email Hunter account to use the extension. It's free and takes 30 seconds.
Create a free account
Sign in
Email Hunter Chrome extension seems not to be associated to your account. Please sign in to continue.
Sign in
You've reached your monthly quota. Please upgrade your account to continue using Email Hunter.
Upgrade


Martin King says he'd like to co-host TV show with photographer wife Jenny McCarthy
“There isn’t a husband and wife team on the TV in Ireland and I think the dynamic would work"
by Ciara PhelanMartin King has said he would like to co-host a TV show with his wife Jenny McCarthy.
Jenny, a celeb photographer, added there’s a gap in the market for an on-screen husband and wife duo.
Martin, who presents the Six O’Clock Show with Muireann O’Connell, told the RTE Guide: “I wouldn’t mind doing a little bit of TV work with this woman.
“I think it would work great, Jenny wouldn’t let me away with anything.”
Jenny, who also appears on Ireland AM, said she loves the adrenlaine rush from appearing on telly.
She added: “There isn’t a husband and wife team on the TV in Ireland and I think the dynamic would work. I just don’t know if I’d have the time.”
How to follow the Irish Mirror on social media
You can like our main Facebook page here.
Our Irish Mirror Sports page - which brings you all your Irish and UK sports news - can be found here.
You can also check out our Irish Mirror GAA sports page.
The Irish Mirror Twitter account is @IrishMirror while our sports account is @MirrorSportIE.
Our Instagram account can be found here.