1
0
mirror of https://github.com/danog/gift.git synced 2024-11-26 11:54:51 +01:00

initial commit

This commit is contained in:
sentientwaffle 2012-02-15 07:51:45 -07:00
commit 3ef68d9840
211 changed files with 5425 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
lib
node_modules

0
.npmignore Normal file
View File

20
LICENSE Normal file
View File

@ -0,0 +1,20 @@
Copyright (c) 2012 [DJG](https://github.com/sentientwaffle)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject
to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

248
README.md Normal file
View File

@ -0,0 +1,248 @@
# Gift
A basic Node.js wrapper for the Git CLI. The API is based on
[Grit](https://github.com/mojombo/grit)
# Installation
$ npm install gift
# API
git = require 'gift'
repo = git "path/to/repo"
# => #<Repo>
## Repo
### Repo#path
`String` - The path to the repository.
### Repo#commits([treeish, [limit, [skip, ]]]callback)
Get a list of commits.
* `treeish` - `String` (optional).
* `limit` - `Integer` (optional).
* `skip` - `Integer` (optional).
* `callback` - `Function` which receives `(err, commits)`, where `commits` is
an `Array` of `Commit`s.
Get the 10 most recent commits to master.
repo.commits (err, commits) ->
Or to a different tag or branch.
repo.commits "v0.0.3", (err, commits) ->
Limit the maximum number of commits returned.
repo.commits "master", 30, (err, commits) ->
Skip some (for pagination):
repo.commits "master", 30, 30, (err, commits) ->
### Repo#tree([treeish]) => Tree
The `Tree` object for the treeish (which defaults to "master").
repo.tree().contents (err, children) ->
for child in children
console.log child.name
### Repo#diff(commitA, commitB, [paths, ]callback)
Get the difference between the trees.
The callback receives `(err, diffs)`.
### Repo#remotes(callback)
Get the repository's remotes.
Receives `(err, remotes)`, where each remote is a Ref.
### Repo#remote_list(callback)
Get a list of the repository's remote names.
Get the string names of each of the remotes.
### Repo#remote_add(name, url, callback)
Equivalent to `git remote add <name> <url>`.
### Repo#remote_fetch(name, callback)
`git fetch <name>`
### Repo#status(callback)
The callback receives `(err, status)`.
### Repo#create_branch(name, callback)
Create a new branch with `name`, and call the callback when complete
with an error, if one occurred.
### Repo#delete_branch(name, callback)
Delete the branch `name`, and call the callback with an error, if one occurred.
### Repo#tags(callback)
Get a list of `Tag`s.
### Repo#create_tag(name, callback)
Create a tab with the given name.
### Repo#delete_tag(name, callback)
Delete the tag with the given name.
### Repo#branches(callback)
`callback` receives `(err, heads)`.
### Repo#create_branch(name, callback)
Create a branch with the given name.
### Repo#delete_branch(delete, callback)
Delete the branch with the given name.
### Repo#branch([branch, ]callback)
Get a branch.
* `branch` - The name of the branch to get. Defaults to the
currently checked out branch.
* `callback` - Receives `(err, head)`.
### Repo#commit(message, [options, ]callback)
Commit some changes.
* `message` - `String`
* `options` -
- `all` - `Boolean`
- `amend` - `Boolean`
* `callback` - Receives `(err)`.
### Repo#add(files, callback)
`git add <files>`
### Repo#remove(files, callback)
`git rm <files>`
### Repo#checkout(treeish, callback)
`git checkout <treeish>`
## Commit
### Commit#id
`String` - The commit's SHA.
### Commit#parents
`Commit[]`
### Commit#tree(callback)
* `callback` - Receives `(err, tree)`.
### Commit#author
`Actor`
### Commit#authored_date
`Date`
### Commit#committer
`Actor`
### Commit#committed_date
`Date`
### Commit#message
`String`
## Head
### Head#name
`String`
### Head#commit
`Commit`
## Tag
### Tag#name
`String`
### Tag#commit
`Commit`
### Tag#message(callback)
The callback receives `(err, message)` (`message` is a String).
### Tag#tagger(callback)
The callback receives `(err, actor)`.
### Tag#tag_date(callback)
The callback receives `(err, date)`.
## Status
### Status#clean
`Boolean`
### Status#files
`Object` - The keys are files, the values objects indicating whether or not
the file is staged, tracked, etc.
Each file has the following properties:
* `type` - "A" for added, "M" for modified, "D" for deleted.
* `staged` - `Boolean`
* `tracked` - `Boolean`
## Actor
### Actor#name
`String`
### Actor#email
`String`
## Tree
### Tree#id
`String` - SHA1
### Tree#contents(callback)
* `callback` - Receives `(err, children)`.
* `children` - An array of `Blob`s, `Tree`s, and `Submodule`s.
### Tree#blobs(callback)
* `callback` - Receives `(err, child_blobs)`.
* `children` - `[Blob]`
### Tree#trees(callback)
* `callback` - Receives `(err, child_trees)`.
* `children` - `[Tree]`
### Tree#find(directory, callback)
* `directory` - `String`
* `callback` - Receives `(err, thing)`.
## Blob
### Blob#id
`String` - SHA1
### Blob#mode
`String`
### Blob#data(callback)
* `callback` - `(err, data)`
## Submodule
### Submodule#id
`String`
### Submodule#name
`String`
### Submodule#mode
`String`
### Submodule#url(callback)
Get the url the submodule points to.
# License
See LICENSE.

31
package.json Normal file
View File

@ -0,0 +1,31 @@
{ "name": "gift"
, "version": "0.0.1"
, "description": "a Git wrapper library"
, "keywords": ["git"]
, "homepage": "https://github.com/sentientwaffle/gift"
, "bugs": {"url": "https://github.com/sentientwaffle/gift/issues"}
, "author":
{ "name": "sentientwaffle"
, "url": "http://sentientwaffle.github.com/"
}
, "main": "./lib/index"
, "scripts":
{ "test": "mocha"
, "prepublish": "coffee -o lib -c src"
}
, "repository":
{ "type": "git"
, "url": "https://github.com/sentientwaffle/gift.git"
}
, "dependencies": {"underscore": "1.x.x"}
, "devDependencies":
{ "should": "0.4.x"
, "mocha": "0.5.x"
}
, "engines": {"node": "> 0.4.1"}
}

16
src/actor.coffee Normal file
View File

@ -0,0 +1,16 @@
module.exports = class Actor
constructor: (@name, @email) ->
# Public: Get a string representation of the Actor.
toString: ->
"#{@name} <#{@email}>"
# Public: Parse an Actor from a "bla <bla@example.com>" string.
#
# Returns Actor.
@from_string: (str) ->
if /<.+>/.test str
[m, name, email] = /(.*) <(.+?)>/.exec str
return new Actor(name, email)
else
return new Actor(str, null)

17
src/blob.coffee Normal file
View File

@ -0,0 +1,17 @@
path = require 'path'
module.exports = class Blob
constructor: (@repo, attrs) ->
{@id, @name, @mode} = attrs
# Public: Get the blob contents.
#
# callback - Receives `(err, data)`.
#
data: (callback) ->
@repo.git "cat-file", {p: true}, @id
, (err, stdout, stderr) ->
return callback err, stdout
toString: ->
"#<Blob '#{@id}'>"

100
src/commit.coffee Normal file
View File

@ -0,0 +1,100 @@
_ = require 'underscore'
Actor = require './actor'
Tree = require './tree'
module.exports = class Commit
constructor: (@repo, @id, parents, tree, @author, @authored_date, @committer, @committed_date, @message) ->
# Public: Get the commit's Tree.
#
# Returns Tree.
@tree = _.memoize => (new Tree this, tree)
# Public: Get the Commit's parent Commits.
#
# Returns an Array of Commits.
@parents = _.memoize =>
_.map parents, (parent) =>
new Commit @repo, parent
# Public: Find the matching commits.
#
# callback - Receives `(err, commits)`
#
@find_all: (repo, ref, options, callback) ->
options = _.extend {pretty: "raw"}, options
repo.git "rev-list", options, ref
, (err, stdout, stderr) =>
return callback err if err
return callback null, @parse_commits(repo, stdout)
@find: (repo, id, callback) ->
options = {pretty: "raw", "max-count": 1}
repo.git "rev-list", options, id
, (err, stdout, stderr) =>
return callback err if err
return callback null, @parse_commits(repo, stdout)[0]
@find_commits: (repo, ids, callback) ->
commits = []
next = (i) ->
if id = ids[i]
Commit.find repo, id, (err, commit) ->
return callback err if err
commits.push commit
next i + 1
# Done: all commits loaded.
else
callback null, commits
next 0
# Internal: Parse the commits from `git rev-list`
#
# Return Commit[]
@parse_commits: (repo, text) ->
commits = []
lines = text.split "\n"
while lines.length
id = _.last lines.shift().split(" ")
tree = _.last lines.shift().split(" ")
parents = []
while /^parent/.test lines[0]
parents.push _.last lines.shift().split(" ")
author_line = lines.shift()
if !/^committer /.test(lines[0])
author_line.push lines.shift()
[author, authored_date] = @actor author_line
committer_line = lines.shift()
if lines[0] && !/^encoding/.test(lines[0])
committer_line.push lines.shift()
[committer, committed_date] = @actor committer_line
# not doing anything with this yet, but it's sometimes there
if /^encoding/.test lines.first
encoding = _.last lines.shift().split(" ")
lines.shift()
message_lines = []
while /^ {4}/.test lines[0]
message_lines.push lines.shift()[4..-1]
while lines[0]? && !lines[0].length
lines.shift()
commits.push new Commit(repo, id, parents, tree, author, authored_date, committer, committed_date, message_lines.join("\n"))
return commits
# Internal: Parse the actor.
#
# Returns [String name and email, Date]
@actor: (line) ->
[m, actor, epoch] = /^.+? (.*) (\d+) .*$/.exec line
return [Actor.from_string(actor), new Date(+epoch)]

61
src/diff.coffee Normal file
View File

@ -0,0 +1,61 @@
Blob = require './blob'
module.exports = class Diff
constructor: (@repo, @a_path, @b_path, a_blob, b_blob
, @a_mode, @b_mode, @new_file, @deleted_file, @diff
, @renamed_file=false, @similarity_index=0) ->
@a_blob = new Blob @repo, {id: a_blob} if a_blob
@b_blob = new Blob @repo, {id: b_blob} if b_blob
# Public: Parse the Diffs from the command output.
#
# text - String stdout of a `git diff` command.
#
# Returns Array of Diff.
@parse: (repo, text) ->
lines = text.split "\n"
diffs = []
while lines.length && lines[0]
[m, a_path, b_path] = ///^diff\s--git\sa/(.+?)\sb/(.+)$///.exec lines.shift()
if /^old mode/.test lines[0]
[m, a_mode] = /^old mode (\d+)/.exec lines.shift()
[m, b_mode] = /^new mode (\d+)/.exec lines.shift()
if !lines.length || /^diff --git/.test(lines[0])
diffs.push new Diff(repo, a_path, b_path, null, null, a_mode, b_mode, false, false, null)
continue
sim_index = 0
new_file = false
deleted_file = false
renamed_file = false
if /^new file/.test lines[0]
[m, b_mode] = /^new file mode (.+)$/.exec lines.shift()
a_mode = null
new_file = true
else if /^deleted file/.test lines[0]
[m, a_mode] = /^deleted file mode (.+)$/.exec lines.shift()
b_mode = null
deleted_file = true
else if m = /^similarity index (\d+)\%/.exec(lines[0])
sim_index = m[1].to_i
renamed_file = true
# shift away the 2 `rename from/to ...` lines
lines.shift()
lines.shift()
[m, a_blob, b_blob, b_mode] = ///^index\s([0-9A-Fa-f]+)\.\.([0-9A-Fa-f]+)\s?(.+)?$///.exec lines.shift()
b_mode = b_mode.trim() if b_mode
diff_lines = []
while lines[0] && !/^diff/.test(lines[0])
diff_lines.push lines.shift()
diff = diff_lines.join "\n"
diffs.push new Diff(repo, a_path, b_path, a_blob, b_blob, a_mode, b_mode, new_file, deleted_file, diff, renamed_file, sim_index)
return diffs

76
src/git.coffee Normal file
View File

@ -0,0 +1,76 @@
fs = require 'fs'
{exec} = require 'child_process'
module.exports = Git = (git_dir, dot_git) ->
dot_git ||= "#{git_dir}/.git"
git = (command, options, args, callback) ->
[callback, args] = [args, callback] if !callback
[callback, options] = [options, callback] if !callback
options ?= {}
options = options_to_argv options
options = options.join " "
args ?= []
args = args.join " " if args instanceof Array
bash = "#{Git.bin} #{command} #{options} #{args}"
exec bash, {cwd: git_dir}, callback
return bash
# Public: Get a list of the remote names.
#
# callback - Receives `(err, names)`.
#
git.list_remotes = (callback) ->
fs.readdir "#{dot_git}/refs/remotes", (err, files) ->
callback err, (files || [])
# Public: Get the ref data string.
#
# type - Such as `remote` or `tag`.
# callback - Receives `(err, stdout)`.
#
git.refs = (type, options, callback) ->
[callback, options] = [options, callback] if !callback
prefix = "refs/#{type}s/"
git "show-ref", (err, text) ->
matches = []
for line in (text || "").split("\n")
continue if !line
[id, name] = line.split(' ')
if name.substr(0, prefix.length) == prefix
matches.push "#{name.substr(prefix.length)} #{id}"
return callback err, matches.join("\n")
return git
# Public: The `git` command.
Git.bin = "git"
# Internal: Transform an Object into command line options.
#
# Returns an Array of String option arguments.
Git.options_to_argv = options_to_argv = (options) ->
argv = []
for key, val of options
if key.length == 1
if val == true
argv.push "-#{key}"
else if val == false
# ignore
else
argv.push "-#{key}"
argv.push val
else
if val == true
argv.push "--#{key}"
else if val == false
# ignore
else
argv.push "--#{key}=#{val}"
return argv

20
src/index.coffee Normal file
View File

@ -0,0 +1,20 @@
{exec} = require 'child_process'
Repo = require './repo'
# Public: Create a Repo from the given path.
#
# Returns Repo.
module.exports = Git = (path, bare=false) ->
return new Repo path, bare
# Public: Initialize a git repository.
#
# path - The directory to run `git init .` in.
# callback - Receives `(err, repo)`.
#
Git.init = (path, callback) ->
exec "git init .", {cwd: git_dir}
, (err, stdout, stderr) ->
return callback err if err
return callback err, (new Repo path)

47
src/ref.coffee Normal file
View File

@ -0,0 +1,47 @@
fs = require 'fs'
Commit = require './commit'
exports.Ref = class Ref
constructor: (@name, @commit) ->
{@repo} = @commit
# Public: Get a String representation of the Ref.
toString: ->
"#<Ref '#{@name}'>"
# Internal: Find all refs.
#
# options - (optional).
#
# Returns Array of Ref.
@find_all: (repo, type, RefClass, callback) ->
repo.git.refs type, {}, (err, text) ->
return callback err if err
names = []
ids = []
for ref in text.split("\n")
continue if !ref
[name, id] = ref.split(' ')
names.push name
ids.push id
Commit.find_commits repo, ids, (err, commits) ->
return callback err if err
refs = []
for name, i in names
refs.push new RefClass name, commits[i]
return callback null, refs
exports.Head = class Head extends Ref
@find_all: (repo, callback) ->
Ref.find_all repo, "head", Head, callback
@current: (repo, callback) ->
fs.readFile "#{repo.dot_git}/HEAD", (err, data) ->
return callback err if err
[m, branch] = /ref: refs\/heads\/([^\s]+)/.exec data
fs.readFile "#{repo.dot_git}/refs/heads/#{branch}", (err, id) ->
Commit.find repo, id, (err, commit) ->
return callback err if err
return callback null, (new Head branch, commit)

224
src/repo.coffee Normal file
View File

@ -0,0 +1,224 @@
_ = require 'underscore'
cmd = require './git'
Commit = require './commit'
Tree = require './tree'
Diff = require './diff'
Tag = require './tag'
Status = require './status'
{Ref, Head} = require './ref'
module.exports = class Repo
constructor: (@path, @bare) ->
if @bare
@dot_git = @path
else
@dot_git = "#{@path}/.git"
@git = cmd @path, @dot_git
# Public: Get a list of commits.
#
# treeish - String (optional).
# limit - Integer (optional).
# skip - Integer (optional).
# callback - Function which receives `(err, commits)`, where `commits` is
# an Array of Commits.
#
# Examples
#
# # Get the 10 most recent commits to master.
# repo.commits (err, commits) ->
#
# # Or to a different tag or branch.
# repo.commits "v0.0.3", (err, commits) ->
#
# # Limit the maximum number of commits returned.
# repo.commits "master", 30, (err, commits) ->
#
# # Skip some (for pagination):
# repo.commits "master", 30, 30, (err, commits) ->
#
commits: (start, limit, skip, callback) ->
[skip, callback] = [callback, skip] if !callback
[limit, callback] = [callback, limit] if !callback
[start, callback] = [callback, start] if !callback
throw new Error "a callback is required" if !callback
start ?= "master"
limit ?= 10
skip ?= 0
Commit.find_all this, start, {"max-count": limit, skip}, callback
# Public: The tree object for the treeish or master.
#
# treeish - String treeish (such as a branch or tag) (optional).
#
# Returns Tree.
tree: (treeish="master") ->
return new Tree this, treeish
# Public: Get the difference between the trees.
#
# commitA - A Commit.
# commitB - A Commit.
# paths - A list of String paths to restrict the difference to (optional).
# callback - A Function which receives `(err, diffs)`.
#
diff: (commitA, commitB, paths, callback) ->
[callback, paths] = [paths, callback] if !callback
paths ?= []
@git "diff", {}, _.flatten([commitA, commitB, "--", paths])
, (err, stdout, stderr) =>
return callback err if err
return callback err, Diff.parse(this, stdout)
# Public: Get the repository's remotes.
#
# callback - Receives `(err, remotes)`.
#
remotes: (callback) ->
Ref.find_all this, "remote", Ref, callback
# Public: List the repository's remotes.
#
# callback - Receives `(err, names)`.
#
remote_list: (callback) ->
@git.list_remotes callback
# Public: Add a remote.
#
# name - String name of the remote.
# url - String url of the remote.
# callback - Receives `(err)`
#
remote_add: (name, url, callback) ->
@git "remote", {}, ["add", name, url]
, (err, stdout, stderr) ->
callback err
# Public: `git fetch <name>`.
#
# name - String name of the remote
# callback - Receives `(err)`.
#
remote_fetch: (name, callback) ->
@git "fetch", {}, name
, (err, stdout, stderr) ->
callback err
# Public: Get the repository's status (`git status`).
#
# callback - Receives `(err, callback)`
#
status: (callback) ->
return new Status(this, callback)
# Public: Get the repository's tags.
#
# callback - Receives `(err, tags)`.
#
tags: (callback) ->
Tag.find_all this, callback
# Public: Create a tag.
#
# name - String
# callback - Receives `(err)`.
#
create_tag: (name, callback) ->
@git "tag", {a: name}, callback
# Public: Delete the tag.
#
# name - String
# callback - Receives `(err)`.
#
delete_tag: (name, callback) ->
@git "tag", {d: name}, callback
# Public: Get a list of branches.
#
# callback - Receives `(err, heads)`.
#
branches: (callback) ->
Head.find_all this, callback
# Public: Create a branch with the given name.
#
# name - String name of the new branch.
# callback - Receives `(err)`.
#
create_branch: (name, callback) ->
@git "branch", {}, name, (err, stdout, stderr) ->
return callback err
# Public: Delete the branch with the given name.
#
# name - String name of the branch to delete.
# callback - Receives `(err)`.
#
delete_branch: (name, callback) ->
@git "branch", {d: true}, name, (err, stdout, stderr) ->
return callback err
# Public: Get the Branch with the given name.
#
# name - String (optional). By default, get the current branch.
# callback - Receives `(err, head)`
#
branch: (name, callback) ->
[name, callback] = [callback, name] if !callback
if !name
Head.current this, callback
else
@branches (err, heads) ->
return callback err if err
for head in heads
return callback null, head if head.name == name
return callback new Error "No branch named '#{name}' found"
# Public: Checkout the treeish.
checkout: (treeish, callback) ->
@git "checkout", {}, treeish, callback
# Public: Commit some code.
#
# message - String
# options - Object (optional).
# "amend" - Boolean
# "all" - Boolean
# callback - Receives `(err)`.
#
commit: (message, options, callback) ->
[options, callback] = [callback, options] if !callback
options = _.extend options, {m: message}
@git "commit", options, (err, stdout, stderr) ->
callback err
# Public: Add files to the index.
#
# files - Array of String paths; or a String path.
# callback - Receives `(err)`.
#
add: (files, callback) ->
files = [files] if _.isString files
@git "add", {}, files, callback
# Public: Remove files from the index.
#
# files - Array of String paths; or a String path.
# callback - Receives `(err)`.
#
remove: (files, callback) ->
files = [files] if _.isString files
@git "rm", {}, files, callback

48
src/status.coffee Normal file
View File

@ -0,0 +1,48 @@
# Public: Create a Status.
#
# repo - A Repo.
# callback - Receives `(err, status)`
#
module.exports = S = (repo, callback) ->
repo.git "status", (err, stdout, stderr) ->
status = new Status repo
status.parse stdout
return callback err, status
BEGIN_STAGED = "# Changes to be committed:"
BEGIN_UNSTAGED = "# Changed but not updated:"
BEGIN_UNTRACKED = "# Untracked files:"
FILE = /^#\s+([^\s]+)[:]\s+(.+)$/
TYPES =
added: "A"
modified: "M"
deleted: "D"
S.Status = class Status
constructor: (@repo) ->
# Internal: Parse the status from stdout of a `git status` command.
parse: (text) ->
@files = {}
@clean = true
state = null
for line in text.split("\n")
@clean = false
if line == BEGIN_STAGED
state = "staged"
else if line == BEGIN_UNSTAGED
state = "unstaged"
else if line == BEGIN_UNTRACKED
state = "untracked"
else if state && match = FILE.exec(line)
file = match[2]
data = switch state
when "staged" then {staged: true, tracked: true}
when "unstaged" then {staged: false, tracked: true}
data.type = TYPES[match[1]]
@files[file] = data
else if state == "untracked" && (match = /^#\s+([^\s]+)$/.exec(line))
file = match[1]
@files[file] = {tracked: false}
return

59
src/submodule.coffee Normal file
View File

@ -0,0 +1,59 @@
module.exports = class Submodule
constructor: (@repo, options) ->
{@id, @name, @mode} = options
# Public: Get the URL of the submodule.
#
# treeish - String treeish to look up the url within.
# callback - Receives `(err, url)`.
#
url: (treeish, callback) ->
[treeish, callback] = [callback, treeish] if !callback
treeish ?= "master"
Submodule.config @repo, treeish, (err, config) =>
return callback err, config?[@name].url
# Internal: Parse the `.gitmodules` file.
#
# repo - A Repo.
# treeish - String
# callback - Receives `(err, config)`, where the config object has
# the submodule names as its keys.
#
# Examples
#
# The following `.gitmodules` file:
#
# [submodule "spoon-knife"]
# path = spoon-knife
# url = git://github.com/octocat/Spoon-Knife.git
#
# would parse to:
#
# { "spoon-knife":
# { "path": "spoon-knife"
# , "url": "git://github.com/octocat/Spoon-Knife.git"
# }
# }
#
@config: (repo, treeish, callback) ->
repo.tree(treeish).find ".gitmodules", (err, blob) ->
return callback err if err
blob.data (err, data) ->
return callback err if err
conf = {}
lines = data.split "\n"
current = null
while lines.length
line = lines.shift()
if match = /^\[submodule "(.+)"\]$/.exec line
current = match[1]
conf[current] = {}
else if match = /^\s+([^\s]+)\s+[=]\s+(.+)$/.exec line
conf[current][match[1]] = match[2]
return callback null, conf

62
src/tag.coffee Normal file
View File

@ -0,0 +1,62 @@
_ = require 'underscore'
Commit = require './commit'
Actor = require './actor'
{Ref} = require './ref'
module.exports = class Tag extends Ref
@find_all: (repo, callback) ->
Ref.find_all repo, "tag", Tag, callback
# Public: Get the tag message.
#
# Returns String.
message: (callback) ->
@lazy (err, data) ->
return callback err if err
return callback null, data.message
# Public: Get the tag author.
#
# Returns Actor.
tagger: (callback) ->
@lazy (err, data) ->
return callback err if err
return callback null, data.tagger
# Public: Get the date that the tag was created.
#
# Returns Date.
tag_date: (callback) ->
@lazy (err, data) ->
return callback err if err
return callback null, data.tag_date
# Internal: Load the tag data.
lazy: (callback) ->
return callback null, @_lazy_data if @_lazy_data
@repo.git "cat-file", {}, ["tag", @name]
, (err, stdout, stderr) =>
return callback err if err
lines = stdout.split "\n"
data = {}
lines.shift() # object 4ae1cc5e6c7bb85b14ecdf221030c71d0654a42e
lines.shift() # type commit
lines.shift() # tag v0.0.2
# bob <bob@example.com>
author_line = lines.shift()
[m, author, epoch] = /^.+? (.*) (\d+) .*$/.exec author_line
data.tagger = Actor.from_string author
data.tag_date = new Date epoch
lines.shift()
message = []
while line = lines.shift()
message.push line
data.message = message.join("\n")
return callback null, (@_lazy_data = data)

103
src/tree.coffee Normal file
View File

@ -0,0 +1,103 @@
_ = require 'underscore'
Blob = require './blob'
Submodule = require './submodule'
module.exports = class Tree
# repo - A Repo.
# options - An Object with properties "id", "name", and "mode";
# or just a String id.
constructor: (@repo, options) ->
if _.isString options
@id = options
else
{@id, @name, @mode} = options
# Public: Get the children of the tree.
#
# callback - Receives `(err, children)`, where children is a list
# of Trees, Blobs, and Submodules.
#
contents: (callback) ->
return callback null, @_contents if @_contents
@repo.git "ls-tree", {}, @id
, (err, stdout, stderr) =>
return callback err if err
@_contents = []
for line in stdout.split("\n")
@_contents.push @content_from_string(line) if line
return callback null, @_contents
# Public: Get the child blobs.
#
# callback - Receives `(err, blobs)`.
#
blobs: (callback) ->
@contents (err, children) ->
return callback err if err
return callback null, _.filter children, (child) ->
child instanceof Blob
# Public: Get the child blobs.
#
# callback - Receives `(err, trees)`.
#
trees: (callback) ->
@contents (err, children) ->
return callback err if err
return callback null, _.filter children, (child) ->
child instanceof Tree
# Public: Find the named object in this tree's contents.
#
# callback - Receives `(err, obj)` where obj is Tree, Blob, or null
# if not found.
#
find: (file, callback) ->
if /\//.test file
[dir, rest] = file.split "/", 2
@trees (err, _trees) =>
for tree in _trees
return callback rest, callback if tree.name == dir
return callback null, null
else
@contents (err, children) ->
return callback err if err
for child in children
if child.name == file
return callback null, child
return callback null, null
# Internal: Parse a Blob or Tree from the line.
#
# line - String
#
# Examples
#
# tree.content_from_string "100644 blob e4ff69dd8f19d770e9731b4bc424ccb695f0b5ad README.md"
# # => #<Blob >
#
# Returns Blob, Tree or Submodule.
content_from_string: (line) ->
[mode, type, id, name] = line.split /[\t ]+/, 4
switch type
when "tree"
new Tree @repo, {id, name, mode}
when "blob"
new Blob @repo, {id, name, mode}
when "link"
new Blob @repo, {id, name, mode}
when "commit"
new Submodule @repo, {id, name, mode}
else
throw new Error "Invalid object type: '#{type}'"
# Public: Get a String representation of the Tree.
#
# Returns String.
toString: ->
"#<Tree '#{@id}'>"

36
test/actor.test.coffee Normal file
View File

@ -0,0 +1,36 @@
should = require 'should'
Actor = require '../src/actor'
describe "Actor", ->
describe ".constructor", ->
actor = new Actor "bob", "bob@example.com"
it "assigns @name", ->
actor.name.should.eql "bob"
it "assigns @email", ->
actor.email.should.eql "bob@example.com"
describe "#toString", ->
actor = new Actor "bob", "bob@example.com"
it "is a string representation of the actor", ->
actor.toString().should.eql "bob <bob@example.com>"
describe ".from_string", ->
describe "with a name and email", ->
actor = Actor.from_string "bob <bob@example.com>"
it "parses the name", ->
actor.name.should.eql "bob"
it "parses the email", ->
actor.email.should.eql "bob@example.com"
describe "with only a name", ->
actor = Actor.from_string "bob"
it "parses the name", ->
actor.name.should.eql "bob"
it "does not parse the email", ->
should.not.exist actor.email

45
test/blob.test.coffee Normal file
View File

@ -0,0 +1,45 @@
should = require 'should'
fixtures = require './fixtures'
git = require '../src'
Blob = require '../src/blob'
describe "Blob", ->
describe "constructor", ->
repo = fixtures.branched
blob = new Blob repo, {name: "X", mode: "Y", id: "abc"}
it "assigns @name", ->
blob.name.should.eql "X"
it "assigns @mode", ->
blob.mode.should.eql "Y"
it "assigns @id", ->
blob.id.should.eql "abc"
describe "#data", ->
describe "of a file off the root", ->
repo = git "#{__dirname}/fixtures/branched"
data = null
before (done) ->
repo.tree().blobs (err, blobs) ->
blobs[0].data (err, _data) ->
data = _data
done err
it "is a string", ->
data.should.be.a "string"
data.should.include "Bla"
describe "of a file in a subdir", ->
repo = git "#{__dirname}/fixtures/branched"
data = null
before (done) ->
repo.tree().trees (err, trees) ->
trees[0].blobs (err, blobs) ->
blobs[0].data (err, _data) ->
data = _data
done err
it "is a string", ->
data.should.be.a "string"
data.should.include "!!!"

35
test/commit.test.coffee Normal file
View File

@ -0,0 +1,35 @@
should = require 'should'
fixtures = require './fixtures'
git = require '../src'
Commit = require '../src/commit'
Tree = require '../src/tree'
describe "Commit", ->
describe "#tree", ->
repo = git "#{__dirname}/fixtures/branched"
tree = null
before (done) ->
repo.commits "master", (err, commits) ->
tree = commits[0].tree()
done err
it "passes a tree", ->
tree.should.be.an.instanceof Tree
describe "#parents", ->
repo = fixtures.branched
parents = null
parent = null
before (done) ->
repo.commits "something", (err, commits) ->
parents = commits[0].parents()
parent = commits[1]
done err
it "is an Array of Commits", ->
parents.should.be.an.instanceof Array
parents[0].should.be.an.instanceof Commit
it "has the parent commit", ->
parents[0].id.should.eql parent.id

98
test/diff.test.coffee Normal file
View File

@ -0,0 +1,98 @@
should = require 'should'
fixtures = require './fixtures'
git = require '../src'
Diff = require '../src/diff'
Blob = require '../src/blob'
describe "Diff", ->
describe ".parse", ->
describe "simple editing", ->
repo = fixtures.tagged
stdout = """
diff --git a/file.txt b/file.txt
index d00491f..48082f7 100644
--- a/file.txt
+++ b/file.txt
@@ -1 +1 @@
-1
+12
"""
diffs = Diff.parse repo, stdout
it "is an Array of Diffs", ->
diffs.should.be.an.instanceof Array
diffs[0].should.be.an.instanceof Diff
it "has one diff", ->
diffs.should.have.lengthOf 1
describe "the first diff", ->
diff = diffs[0]
it "has the repo", ->
diff.repo.should.eql repo
for blob in ["a_blob", "b_blob"]
it "has a #{blob}", ->
diff[blob].should.be.an.instanceof Blob
for path in ["a_path", "b_path"]
it "has a #{path}", ->
diff[path].should.eql "file.txt"
it "has a b_mode", ->
diff.b_mode.should.eql "100644"
for change in ["new_file", "renamed_file", "deleted_file"]
it "#{change} is false", ->
diff[change].should.be.false
it "has a similarity_index of 0", ->
diff.similarity_index.should.eql 0
describe "delete a file", ->
repo = fixtures.branched
stdout = """
diff --git a/README.md b/README.md
index e4ff69d..c0efd1c 100644
--- a/README.md
+++ b/README.md
@@ -1 +1 @@
-Bla
+Bla2
diff --git a/some/hi.txt b/some/hi.txt
deleted file mode 100644
index 6f1de24..0000000
--- a/some/hi.txt
+++ /dev/null
@@ -1 +0,0 @@
-!!!
"""
diffs = Diff.parse repo, stdout
it "has 2 diffs", ->
diffs.should.have.lengthOf 2
describe "the second diff", ->
diff = diffs[1]
it "deletes a file", ->
diff.deleted_file.should.be.true
describe "create a file", ->
repo = fixtures.branched
stdout = """
diff --git a/some/hi.txt b/some/hi.txt
new file mode 100644
index 0000000..6f1de24
--- /dev/null
+++ b/some/hi.txt
@@ -0,0 +1 @@
+!!!
"""
diffs = Diff.parse repo, stdout
it "creates a file", ->
diffs[0].new_file.should.be.true

12
test/fixtures.coffee Normal file
View File

@ -0,0 +1,12 @@
git = require '../src'
dir = "#{__dirname}/fixtures"
module.exports =
branched: git("#{dir}/branched", true)
checkout: git("#{dir}/checkout", true)
remotes: git("#{dir}/remotes", true)
simple: git("#{dir}/simple", true)
status: git("#{dir}/status", true)
submodule: git("#{dir}/submodule", true)
tagged: git("#{dir}/tagged", true)

1
test/fixtures/branched/COMMIT_EDITMSG vendored Normal file
View File

@ -0,0 +1 @@
add a sub dir

1
test/fixtures/branched/HEAD vendored Normal file
View File

@ -0,0 +1 @@
ref: refs/heads/master

5
test/fixtures/branched/config vendored Normal file
View File

@ -0,0 +1,5 @@
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true

1
test/fixtures/branched/description vendored Normal file
View File

@ -0,0 +1 @@
Unnamed repository; edit this file 'description' to name the repository.

View File

@ -0,0 +1,15 @@
#!/bin/sh
#
# An example hook script to check the commit log message taken by
# applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit. The hook is
# allowed to edit the commit message file.
#
# To enable this hook, rename this file to "applypatch-msg".
. git-sh-setup
test -x "$GIT_DIR/hooks/commit-msg" &&
exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
:

View File

@ -0,0 +1,24 @@
#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by git-commit with one argument, the name of the file
# that has the commit message. The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit. The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".
# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
# This example catches duplicate Signed-off-by lines.
test "" = "$(grep '^Signed-off-by: ' "$1" |
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
echo >&2 Duplicate Signed-off-by lines.
exit 1
}

View File

@ -0,0 +1,8 @@
#!/bin/sh
#
# An example hook script that is called after a successful
# commit is made.
#
# To enable this hook, rename this file to "post-commit".
: Nothing

View File

@ -0,0 +1,15 @@
#!/bin/sh
#
# An example hook script for the "post-receive" event.
#
# The "post-receive" script is run after receive-pack has accepted a pack
# and the repository has been updated. It is passed arguments in through
# stdin in the form
# <oldrev> <newrev> <refname>
# For example:
# aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master
#
# see contrib/hooks/ for a sample, or uncomment the next line and
# rename the file to "post-receive".
#. /usr/share/doc/git-core/contrib/hooks/post-receive-email

View File

@ -0,0 +1,8 @@
#!/bin/sh
#
# An example hook script to prepare a packed repository for use over
# dumb transports.
#
# To enable this hook, rename this file to "post-update".
exec git-update-server-info

View File

@ -0,0 +1,14 @@
#!/bin/sh
#
# An example hook script to verify what is about to be committed
# by applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-applypatch".
. git-sh-setup
test -x "$GIT_DIR/hooks/pre-commit" &&
exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
:

View File

@ -0,0 +1,46 @@
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by git-commit with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit".
if git-rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# If you want to allow non-ascii filenames set this variable to true.
allownonascii=$(git config hooks.allownonascii)
# Cross platform projects tend to avoid non-ascii filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
# Note that the use of brackets around a tr range is ok here, (it's
# even required, for portability to Solaris 10's /usr/bin/tr), since
# the square bracket bytes happen to fall in the designated range.
test "$(git diff --cached --name-only --diff-filter=A -z $against |
LC_ALL=C tr -d '[ -~]\0')"
then
echo "Error: Attempt to add a non-ascii file name."
echo
echo "This can cause problems if you want to work"
echo "with people on other platforms."
echo
echo "To be portable it is advisable to rename the file ..."
echo
echo "If you know what you are doing you can disable this"
echo "check using:"
echo
echo " git config hooks.allownonascii true"
echo
exit 1
fi
exec git diff-index --check --cached $against --

169
test/fixtures/branched/hooks/pre-rebase.sample vendored Executable file
View File

@ -0,0 +1,169 @@
#!/bin/sh
#
# Copyright (c) 2006, 2008 Junio C Hamano
#
# The "pre-rebase" hook is run just before "git-rebase" starts doing
# its job, and can prevent the command from running by exiting with
# non-zero status.
#
# The hook is called with the following parameters:
#
# $1 -- the upstream the series was forked from.
# $2 -- the branch being rebased (or empty when rebasing the current branch).
#
# This sample shows how to prevent topic branches that are already
# merged to 'next' branch from getting rebased, because allowing it
# would result in rebasing already published history.
publish=next
basebranch="$1"
if test "$#" = 2
then
topic="refs/heads/$2"
else
topic=`git symbolic-ref HEAD` ||
exit 0 ;# we do not interrupt rebasing detached HEAD
fi
case "$topic" in
refs/heads/??/*)
;;
*)
exit 0 ;# we do not interrupt others.
;;
esac
# Now we are dealing with a topic branch being rebased
# on top of master. Is it OK to rebase it?
# Does the topic really exist?
git show-ref -q "$topic" || {
echo >&2 "No such branch $topic"
exit 1
}
# Is topic fully merged to master?
not_in_master=`git-rev-list --pretty=oneline ^master "$topic"`
if test -z "$not_in_master"
then
echo >&2 "$topic is fully merged to master; better remove it."
exit 1 ;# we could allow it, but there is no point.
fi
# Is topic ever merged to next? If so you should not be rebasing it.
only_next_1=`git-rev-list ^master "^$topic" ${publish} | sort`
only_next_2=`git-rev-list ^master ${publish} | sort`
if test "$only_next_1" = "$only_next_2"
then
not_in_topic=`git-rev-list "^$topic" master`
if test -z "$not_in_topic"
then
echo >&2 "$topic is already up-to-date with master"
exit 1 ;# we could allow it, but there is no point.
else
exit 0
fi
else
not_in_next=`git-rev-list --pretty=oneline ^${publish} "$topic"`
perl -e '
my $topic = $ARGV[0];
my $msg = "* $topic has commits already merged to public branch:\n";
my (%not_in_next) = map {
/^([0-9a-f]+) /;
($1 => 1);
} split(/\n/, $ARGV[1]);
for my $elem (map {
/^([0-9a-f]+) (.*)$/;
[$1 => $2];
} split(/\n/, $ARGV[2])) {
if (!exists $not_in_next{$elem->[0]}) {
if ($msg) {
print STDERR $msg;
undef $msg;
}
print STDERR " $elem->[1]\n";
}
}
' "$topic" "$not_in_next" "$not_in_master"
exit 1
fi
exit 0
################################################################
This sample hook safeguards topic branches that have been
published from being rewound.
The workflow assumed here is:
* Once a topic branch forks from "master", "master" is never
merged into it again (either directly or indirectly).
* Once a topic branch is fully cooked and merged into "master",
it is deleted. If you need to build on top of it to correct
earlier mistakes, a new topic branch is created by forking at
the tip of the "master". This is not strictly necessary, but
it makes it easier to keep your history simple.
* Whenever you need to test or publish your changes to topic
branches, merge them into "next" branch.
The script, being an example, hardcodes the publish branch name
to be "next", but it is trivial to make it configurable via
$GIT_DIR/config mechanism.
With this workflow, you would want to know:
(1) ... if a topic branch has ever been merged to "next". Young
topic branches can have stupid mistakes you would rather
clean up before publishing, and things that have not been
merged into other branches can be easily rebased without
affecting other people. But once it is published, you would
not want to rewind it.
(2) ... if a topic branch has been fully merged to "master".
Then you can delete it. More importantly, you should not
build on top of it -- other people may already want to
change things related to the topic as patches against your
"master", so if you need further changes, it is better to
fork the topic (perhaps with the same name) afresh from the
tip of "master".
Let's look at this example:
o---o---o---o---o---o---o---o---o---o "next"
/ / / /
/ a---a---b A / /
/ / / /
/ / c---c---c---c B /
/ / / \ /
/ / / b---b C \ /
/ / / / \ /
---o---o---o---o---o---o---o---o---o---o---o "master"
A, B and C are topic branches.
* A has one fix since it was merged up to "next".
* B has finished. It has been fully merged up to "master" and "next",
and is ready to be deleted.
* C has not merged to "next" at all.
We would want to allow C to be rebased, refuse A, and encourage
B to be deleted.
To compute (1):
git-rev-list ^master ^topic next
git-rev-list ^master next
if these match, topic has not merged in next at all.
To compute (2):
git-rev-list master..topic
if this is empty, it is fully merged to "master".

View File

@ -0,0 +1,36 @@
#!/bin/sh
#
# An example hook script to prepare the commit log message.
# Called by git-commit with the name of the file that has the
# commit message, followed by the description of the commit
# message's source. The hook's purpose is to edit the commit
# message file. If the hook fails with a non-zero status,
# the commit is aborted.
#
# To enable this hook, rename this file to "prepare-commit-msg".
# This hook includes three examples. The first comments out the
# "Conflicts:" part of a merge commit.
#
# The second includes the output of "git diff --name-status -r"
# into the message, just before the "git status" output. It is
# commented because it doesn't cope with --amend or with squashed
# commits.
#
# The third example adds a Signed-off-by line to the message, that can
# still be edited. This is rarely a good idea.
case "$2,$3" in
merge,)
perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
# ,|template,)
# perl -i.bak -pe '
# print "\n" . `git diff --cached --name-status -r`
# if /^#/ && $first++ == 0' "$1" ;;
*) ;;
esac
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"

128
test/fixtures/branched/hooks/update.sample vendored Executable file
View File

@ -0,0 +1,128 @@
#!/bin/sh
#
# An example hook script to blocks unannotated tags from entering.
# Called by git-receive-pack with arguments: refname sha1-old sha1-new
#
# To enable this hook, rename this file to "update".
#
# Config
# ------
# hooks.allowunannotated
# This boolean sets whether unannotated tags will be allowed into the
# repository. By default they won't be.
# hooks.allowdeletetag
# This boolean sets whether deleting tags will be allowed in the
# repository. By default they won't be.
# hooks.allowmodifytag
# This boolean sets whether a tag may be modified after creation. By default
# it won't be.
# hooks.allowdeletebranch
# This boolean sets whether deleting branches will be allowed in the
# repository. By default they won't be.
# hooks.denycreatebranch
# This boolean sets whether remotely creating branches will be denied
# in the repository. By default this is allowed.
#
# --- Command line
refname="$1"
oldrev="$2"
newrev="$3"
# --- Safety check
if [ -z "$GIT_DIR" ]; then
echo "Don't run this script from the command line." >&2
echo " (if you want, you could supply GIT_DIR then run" >&2
echo " $0 <ref> <oldrev> <newrev>)" >&2
exit 1
fi
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
exit 1
fi
# --- Config
allowunannotated=$(git config --bool hooks.allowunannotated)
allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
denycreatebranch=$(git config --bool hooks.denycreatebranch)
allowdeletetag=$(git config --bool hooks.allowdeletetag)
allowmodifytag=$(git config --bool hooks.allowmodifytag)
# check for no description
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
case "$projectdesc" in
"Unnamed repository"* | "")
echo "*** Project description file hasn't been set" >&2
exit 1
;;
esac
# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
zero="0000000000000000000000000000000000000000"
if [ "$newrev" = "$zero" ]; then
newrev_type=delete
else
newrev_type=$(git-cat-file -t $newrev)
fi
case "$refname","$newrev_type" in
refs/tags/*,commit)
# un-annotated tag
short_refname=${refname##refs/tags/}
if [ "$allowunannotated" != "true" ]; then
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
exit 1
fi
;;
refs/tags/*,delete)
# delete tag
if [ "$allowdeletetag" != "true" ]; then
echo "*** Deleting a tag is not allowed in this repository" >&2
exit 1
fi
;;
refs/tags/*,tag)
# annotated tag
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
then
echo "*** Tag '$refname' already exists." >&2
echo "*** Modifying a tag is not allowed in this repository." >&2
exit 1
fi
;;
refs/heads/*,commit)
# branch
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
echo "*** Creating a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/heads/*,delete)
# delete branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/remotes/*,commit)
# tracking branch
;;
refs/remotes/*,delete)
# delete tracking branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
exit 1
fi
;;
*)
# Anything else (is there anything else?)
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
exit 1
;;
esac
# --- Finished
exit 0

BIN
test/fixtures/branched/index vendored Normal file

Binary file not shown.

6
test/fixtures/branched/info/exclude vendored Normal file
View File

@ -0,0 +1,6 @@
# git-ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~

7
test/fixtures/branched/logs/HEAD vendored Normal file
View File

@ -0,0 +1,7 @@
0000000000000000000000000000000000000000 b045ec4b14c60f03329654266478b6e8b92b33c5 sentientwaffle <sentientwaffle@gmail.com> 1328999490 -0700 commit (initial): 1
b045ec4b14c60f03329654266478b6e8b92b33c5 b045ec4b14c60f03329654266478b6e8b92b33c5 sentientwaffle <sentientwaffle@gmail.com> 1328999503 -0700 checkout: moving from master to something
b045ec4b14c60f03329654266478b6e8b92b33c5 7783d64e077617ab7b84fe9726f721e921b9623b sentientwaffle <sentientwaffle@gmail.com> 1328999518 -0700 commit: 2
7783d64e077617ab7b84fe9726f721e921b9623b b045ec4b14c60f03329654266478b6e8b92b33c5 sentientwaffle <sentientwaffle@gmail.com> 1328999521 -0700 checkout: moving from something to master
b045ec4b14c60f03329654266478b6e8b92b33c5 7783d64e077617ab7b84fe9726f721e921b9623b sentientwaffle <sentientwaffle@gmail.com> 1329001555 -0700 checkout: moving from master to something
7783d64e077617ab7b84fe9726f721e921b9623b b045ec4b14c60f03329654266478b6e8b92b33c5 sentientwaffle <sentientwaffle@gmail.com> 1329013635 -0700 checkout: moving from something to master
b045ec4b14c60f03329654266478b6e8b92b33c5 913318e66e9beed3e89e9c402c1d6585ef3f7e6f sentientwaffle <sentientwaffle@gmail.com> 1329013671 -0700 commit: add a sub dir

View File

@ -0,0 +1,2 @@
0000000000000000000000000000000000000000 b045ec4b14c60f03329654266478b6e8b92b33c5 sentientwaffle <sentientwaffle@gmail.com> 1328999490 -0700 commit (initial): 1
b045ec4b14c60f03329654266478b6e8b92b33c5 913318e66e9beed3e89e9c402c1d6585ef3f7e6f sentientwaffle <sentientwaffle@gmail.com> 1329013671 -0700 commit: add a sub dir

View File

@ -0,0 +1,2 @@
0000000000000000000000000000000000000000 b045ec4b14c60f03329654266478b6e8b92b33c5 sentientwaffle <sentientwaffle@gmail.com> 1328999503 -0700 branch: Created from HEAD
b045ec4b14c60f03329654266478b6e8b92b33c5 7783d64e077617ab7b84fe9726f721e921b9623b sentientwaffle <sentientwaffle@gmail.com> 1328999518 -0700 commit: 2

View File

@ -0,0 +1,2 @@
x¥ŽÁ
1 D=÷+òJÚfÓDü•6muÁue·âïÛ«gÃ0ó]—eîàˆlpY¤bj¬¢mDlSeOÃ1JœÌ+mõÙ!#MU)[RƆÞ;á‰3…˜¹Æ,.{¯“Iï~_7ØÇhú¤Öοùz[Òü8éº\ÀZÏÁ¢í¸Úë_“J<E2809C>û;C™7óPxN

View File

@ -0,0 +1 @@
913318e66e9beed3e89e9c402c1d6585ef3f7e6f

View File

@ -0,0 +1 @@
7783d64e077617ab7b84fe9726f721e921b9623b

1
test/fixtures/checkout/COMMIT_EDITMSG vendored Normal file
View File

@ -0,0 +1 @@
commit 1

1
test/fixtures/checkout/HEAD vendored Normal file
View File

@ -0,0 +1 @@
ref: refs/heads/master

5
test/fixtures/checkout/config vendored Normal file
View File

@ -0,0 +1,5 @@
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true

1
test/fixtures/checkout/description vendored Normal file
View File

@ -0,0 +1 @@
Unnamed repository; edit this file 'description' to name the repository.

View File

@ -0,0 +1,15 @@
#!/bin/sh
#
# An example hook script to check the commit log message taken by
# applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit. The hook is
# allowed to edit the commit message file.
#
# To enable this hook, rename this file to "applypatch-msg".
. git-sh-setup
test -x "$GIT_DIR/hooks/commit-msg" &&
exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
:

View File

@ -0,0 +1,24 @@
#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by git-commit with one argument, the name of the file
# that has the commit message. The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit. The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".
# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
# This example catches duplicate Signed-off-by lines.
test "" = "$(grep '^Signed-off-by: ' "$1" |
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
echo >&2 Duplicate Signed-off-by lines.
exit 1
}

View File

@ -0,0 +1,8 @@
#!/bin/sh
#
# An example hook script that is called after a successful
# commit is made.
#
# To enable this hook, rename this file to "post-commit".
: Nothing

View File

@ -0,0 +1,15 @@
#!/bin/sh
#
# An example hook script for the "post-receive" event.
#
# The "post-receive" script is run after receive-pack has accepted a pack
# and the repository has been updated. It is passed arguments in through
# stdin in the form
# <oldrev> <newrev> <refname>
# For example:
# aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master
#
# see contrib/hooks/ for a sample, or uncomment the next line and
# rename the file to "post-receive".
#. /usr/share/doc/git-core/contrib/hooks/post-receive-email

View File

@ -0,0 +1,8 @@
#!/bin/sh
#
# An example hook script to prepare a packed repository for use over
# dumb transports.
#
# To enable this hook, rename this file to "post-update".
exec git-update-server-info

View File

@ -0,0 +1,14 @@
#!/bin/sh
#
# An example hook script to verify what is about to be committed
# by applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-applypatch".
. git-sh-setup
test -x "$GIT_DIR/hooks/pre-commit" &&
exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
:

View File

@ -0,0 +1,46 @@
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by git-commit with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit".
if git-rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# If you want to allow non-ascii filenames set this variable to true.
allownonascii=$(git config hooks.allownonascii)
# Cross platform projects tend to avoid non-ascii filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
# Note that the use of brackets around a tr range is ok here, (it's
# even required, for portability to Solaris 10's /usr/bin/tr), since
# the square bracket bytes happen to fall in the designated range.
test "$(git diff --cached --name-only --diff-filter=A -z $against |
LC_ALL=C tr -d '[ -~]\0')"
then
echo "Error: Attempt to add a non-ascii file name."
echo
echo "This can cause problems if you want to work"
echo "with people on other platforms."
echo
echo "To be portable it is advisable to rename the file ..."
echo
echo "If you know what you are doing you can disable this"
echo "check using:"
echo
echo " git config hooks.allownonascii true"
echo
exit 1
fi
exec git diff-index --check --cached $against --

169
test/fixtures/checkout/hooks/pre-rebase.sample vendored Executable file
View File

@ -0,0 +1,169 @@
#!/bin/sh
#
# Copyright (c) 2006, 2008 Junio C Hamano
#
# The "pre-rebase" hook is run just before "git-rebase" starts doing
# its job, and can prevent the command from running by exiting with
# non-zero status.
#
# The hook is called with the following parameters:
#
# $1 -- the upstream the series was forked from.
# $2 -- the branch being rebased (or empty when rebasing the current branch).
#
# This sample shows how to prevent topic branches that are already
# merged to 'next' branch from getting rebased, because allowing it
# would result in rebasing already published history.
publish=next
basebranch="$1"
if test "$#" = 2
then
topic="refs/heads/$2"
else
topic=`git symbolic-ref HEAD` ||
exit 0 ;# we do not interrupt rebasing detached HEAD
fi
case "$topic" in
refs/heads/??/*)
;;
*)
exit 0 ;# we do not interrupt others.
;;
esac
# Now we are dealing with a topic branch being rebased
# on top of master. Is it OK to rebase it?
# Does the topic really exist?
git show-ref -q "$topic" || {
echo >&2 "No such branch $topic"
exit 1
}
# Is topic fully merged to master?
not_in_master=`git-rev-list --pretty=oneline ^master "$topic"`
if test -z "$not_in_master"
then
echo >&2 "$topic is fully merged to master; better remove it."
exit 1 ;# we could allow it, but there is no point.
fi
# Is topic ever merged to next? If so you should not be rebasing it.
only_next_1=`git-rev-list ^master "^$topic" ${publish} | sort`
only_next_2=`git-rev-list ^master ${publish} | sort`
if test "$only_next_1" = "$only_next_2"
then
not_in_topic=`git-rev-list "^$topic" master`
if test -z "$not_in_topic"
then
echo >&2 "$topic is already up-to-date with master"
exit 1 ;# we could allow it, but there is no point.
else
exit 0
fi
else
not_in_next=`git-rev-list --pretty=oneline ^${publish} "$topic"`
perl -e '
my $topic = $ARGV[0];
my $msg = "* $topic has commits already merged to public branch:\n";
my (%not_in_next) = map {
/^([0-9a-f]+) /;
($1 => 1);
} split(/\n/, $ARGV[1]);
for my $elem (map {
/^([0-9a-f]+) (.*)$/;
[$1 => $2];
} split(/\n/, $ARGV[2])) {
if (!exists $not_in_next{$elem->[0]}) {
if ($msg) {
print STDERR $msg;
undef $msg;
}
print STDERR " $elem->[1]\n";
}
}
' "$topic" "$not_in_next" "$not_in_master"
exit 1
fi
exit 0
################################################################
This sample hook safeguards topic branches that have been
published from being rewound.
The workflow assumed here is:
* Once a topic branch forks from "master", "master" is never
merged into it again (either directly or indirectly).
* Once a topic branch is fully cooked and merged into "master",
it is deleted. If you need to build on top of it to correct
earlier mistakes, a new topic branch is created by forking at
the tip of the "master". This is not strictly necessary, but
it makes it easier to keep your history simple.
* Whenever you need to test or publish your changes to topic
branches, merge them into "next" branch.
The script, being an example, hardcodes the publish branch name
to be "next", but it is trivial to make it configurable via
$GIT_DIR/config mechanism.
With this workflow, you would want to know:
(1) ... if a topic branch has ever been merged to "next". Young
topic branches can have stupid mistakes you would rather
clean up before publishing, and things that have not been
merged into other branches can be easily rebased without
affecting other people. But once it is published, you would
not want to rewind it.
(2) ... if a topic branch has been fully merged to "master".
Then you can delete it. More importantly, you should not
build on top of it -- other people may already want to
change things related to the topic as patches against your
"master", so if you need further changes, it is better to
fork the topic (perhaps with the same name) afresh from the
tip of "master".
Let's look at this example:
o---o---o---o---o---o---o---o---o---o "next"
/ / / /
/ a---a---b A / /
/ / / /
/ / c---c---c---c B /
/ / / \ /
/ / / b---b C \ /
/ / / / \ /
---o---o---o---o---o---o---o---o---o---o---o "master"
A, B and C are topic branches.
* A has one fix since it was merged up to "next".
* B has finished. It has been fully merged up to "master" and "next",
and is ready to be deleted.
* C has not merged to "next" at all.
We would want to allow C to be rebased, refuse A, and encourage
B to be deleted.
To compute (1):
git-rev-list ^master ^topic next
git-rev-list ^master next
if these match, topic has not merged in next at all.
To compute (2):
git-rev-list master..topic
if this is empty, it is fully merged to "master".

View File

@ -0,0 +1,36 @@
#!/bin/sh
#
# An example hook script to prepare the commit log message.
# Called by git-commit with the name of the file that has the
# commit message, followed by the description of the commit
# message's source. The hook's purpose is to edit the commit
# message file. If the hook fails with a non-zero status,
# the commit is aborted.
#
# To enable this hook, rename this file to "prepare-commit-msg".
# This hook includes three examples. The first comments out the
# "Conflicts:" part of a merge commit.
#
# The second includes the output of "git diff --name-status -r"
# into the message, just before the "git status" output. It is
# commented because it doesn't cope with --amend or with squashed
# commits.
#
# The third example adds a Signed-off-by line to the message, that can
# still be edited. This is rarely a good idea.
case "$2,$3" in
merge,)
perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
# ,|template,)
# perl -i.bak -pe '
# print "\n" . `git diff --cached --name-status -r`
# if /^#/ && $first++ == 0' "$1" ;;
*) ;;
esac
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"

128
test/fixtures/checkout/hooks/update.sample vendored Executable file
View File

@ -0,0 +1,128 @@
#!/bin/sh
#
# An example hook script to blocks unannotated tags from entering.
# Called by git-receive-pack with arguments: refname sha1-old sha1-new
#
# To enable this hook, rename this file to "update".
#
# Config
# ------
# hooks.allowunannotated
# This boolean sets whether unannotated tags will be allowed into the
# repository. By default they won't be.
# hooks.allowdeletetag
# This boolean sets whether deleting tags will be allowed in the
# repository. By default they won't be.
# hooks.allowmodifytag
# This boolean sets whether a tag may be modified after creation. By default
# it won't be.
# hooks.allowdeletebranch
# This boolean sets whether deleting branches will be allowed in the
# repository. By default they won't be.
# hooks.denycreatebranch
# This boolean sets whether remotely creating branches will be denied
# in the repository. By default this is allowed.
#
# --- Command line
refname="$1"
oldrev="$2"
newrev="$3"
# --- Safety check
if [ -z "$GIT_DIR" ]; then
echo "Don't run this script from the command line." >&2
echo " (if you want, you could supply GIT_DIR then run" >&2
echo " $0 <ref> <oldrev> <newrev>)" >&2
exit 1
fi
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
exit 1
fi
# --- Config
allowunannotated=$(git config --bool hooks.allowunannotated)
allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
denycreatebranch=$(git config --bool hooks.denycreatebranch)
allowdeletetag=$(git config --bool hooks.allowdeletetag)
allowmodifytag=$(git config --bool hooks.allowmodifytag)
# check for no description
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
case "$projectdesc" in
"Unnamed repository"* | "")
echo "*** Project description file hasn't been set" >&2
exit 1
;;
esac
# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
zero="0000000000000000000000000000000000000000"
if [ "$newrev" = "$zero" ]; then
newrev_type=delete
else
newrev_type=$(git-cat-file -t $newrev)
fi
case "$refname","$newrev_type" in
refs/tags/*,commit)
# un-annotated tag
short_refname=${refname##refs/tags/}
if [ "$allowunannotated" != "true" ]; then
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
exit 1
fi
;;
refs/tags/*,delete)
# delete tag
if [ "$allowdeletetag" != "true" ]; then
echo "*** Deleting a tag is not allowed in this repository" >&2
exit 1
fi
;;
refs/tags/*,tag)
# annotated tag
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
then
echo "*** Tag '$refname' already exists." >&2
echo "*** Modifying a tag is not allowed in this repository." >&2
exit 1
fi
;;
refs/heads/*,commit)
# branch
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
echo "*** Creating a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/heads/*,delete)
# delete branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/remotes/*,commit)
# tracking branch
;;
refs/remotes/*,delete)
# delete tracking branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
exit 1
fi
;;
*)
# Anything else (is there anything else?)
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
exit 1
;;
esac
# --- Finished
exit 0

BIN
test/fixtures/checkout/index vendored Normal file

Binary file not shown.

6
test/fixtures/checkout/info/exclude vendored Normal file
View File

@ -0,0 +1,6 @@
# git-ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~

100
test/fixtures/checkout/logs/HEAD vendored Normal file
View File

@ -0,0 +1,100 @@
0000000000000000000000000000000000000000 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248161 -0700 commit (initial): commit 1
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248175 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248189 -0700 checkout: moving from b2 to b3
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248244 -0700 checkout: moving from b3 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248321 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248321 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248322 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248322 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248323 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248323 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248473 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248473 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248474 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248474 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248475 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248475 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248476 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248476 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248477 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248477 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248601 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248601 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248847 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248847 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248858 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248858 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248860 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248860 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248862 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248862 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329249013 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329249013 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329249035 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329249035 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329249036 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329249036 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329251274 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329251274 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329251361 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329251362 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329251374 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329251374 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329251484 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329251484 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252221 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252221 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252236 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252236 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252258 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252258 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252268 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252268 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252292 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252292 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252335 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252335 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252659 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252659 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252671 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252671 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252678 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252678 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252700 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252700 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252712 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252712 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252716 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252716 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252723 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329252723 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329253157 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329253157 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329253172 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329253172 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329253180 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329253180 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329253190 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329253190 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329253560 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329253560 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329255269 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329255269 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329257716 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329257716 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329257834 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329257834 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329257882 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329257882 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329257891 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329257891 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329258056 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329258056 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329271222 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329271222 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329271295 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329271295 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329274841 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329274841 -0700 checkout: moving from b2 to master
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329316383 -0700 checkout: moving from master to b2
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329316383 -0700 checkout: moving from b2 to master

View File

@ -0,0 +1 @@
0000000000000000000000000000000000000000 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248175 -0700 branch: Created from HEAD

View File

@ -0,0 +1 @@
0000000000000000000000000000000000000000 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248189 -0700 branch: Created from HEAD

View File

@ -0,0 +1 @@
0000000000000000000000000000000000000000 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248161 -0700 commit (initial): commit 1

1
test/fixtures/checkout/refs/heads/b2 vendored Normal file
View File

@ -0,0 +1 @@
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa

1
test/fixtures/checkout/refs/heads/b3 vendored Normal file
View File

@ -0,0 +1 @@
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa

View File

@ -0,0 +1 @@
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa

1
test/fixtures/remotes/HEAD vendored Normal file
View File

@ -0,0 +1 @@
ref: refs/heads/master

11
test/fixtures/remotes/config vendored Normal file
View File

@ -0,0 +1,11 @@
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
url = git@github.com:octocat/Spoon-Knife.git
[branch "master"]
remote = origin
merge = refs/heads/master

1
test/fixtures/remotes/description vendored Normal file
View File

@ -0,0 +1 @@
Unnamed repository; edit this file 'description' to name the repository.

View File

@ -0,0 +1,15 @@
#!/bin/sh
#
# An example hook script to check the commit log message taken by
# applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit. The hook is
# allowed to edit the commit message file.
#
# To enable this hook, rename this file to "applypatch-msg".
. git-sh-setup
test -x "$GIT_DIR/hooks/commit-msg" &&
exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
:

24
test/fixtures/remotes/hooks/commit-msg.sample vendored Executable file
View File

@ -0,0 +1,24 @@
#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by git-commit with one argument, the name of the file
# that has the commit message. The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit. The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".
# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
# This example catches duplicate Signed-off-by lines.
test "" = "$(grep '^Signed-off-by: ' "$1" |
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
echo >&2 Duplicate Signed-off-by lines.
exit 1
}

View File

@ -0,0 +1,8 @@
#!/bin/sh
#
# An example hook script that is called after a successful
# commit is made.
#
# To enable this hook, rename this file to "post-commit".
: Nothing

View File

@ -0,0 +1,15 @@
#!/bin/sh
#
# An example hook script for the "post-receive" event.
#
# The "post-receive" script is run after receive-pack has accepted a pack
# and the repository has been updated. It is passed arguments in through
# stdin in the form
# <oldrev> <newrev> <refname>
# For example:
# aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master
#
# see contrib/hooks/ for a sample, or uncomment the next line and
# rename the file to "post-receive".
#. /usr/share/doc/git-core/contrib/hooks/post-receive-email

View File

@ -0,0 +1,8 @@
#!/bin/sh
#
# An example hook script to prepare a packed repository for use over
# dumb transports.
#
# To enable this hook, rename this file to "post-update".
exec git-update-server-info

View File

@ -0,0 +1,14 @@
#!/bin/sh
#
# An example hook script to verify what is about to be committed
# by applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-applypatch".
. git-sh-setup
test -x "$GIT_DIR/hooks/pre-commit" &&
exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
:

46
test/fixtures/remotes/hooks/pre-commit.sample vendored Executable file
View File

@ -0,0 +1,46 @@
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by git-commit with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit".
if git-rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# If you want to allow non-ascii filenames set this variable to true.
allownonascii=$(git config hooks.allownonascii)
# Cross platform projects tend to avoid non-ascii filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
# Note that the use of brackets around a tr range is ok here, (it's
# even required, for portability to Solaris 10's /usr/bin/tr), since
# the square bracket bytes happen to fall in the designated range.
test "$(git diff --cached --name-only --diff-filter=A -z $against |
LC_ALL=C tr -d '[ -~]\0')"
then
echo "Error: Attempt to add a non-ascii file name."
echo
echo "This can cause problems if you want to work"
echo "with people on other platforms."
echo
echo "To be portable it is advisable to rename the file ..."
echo
echo "If you know what you are doing you can disable this"
echo "check using:"
echo
echo " git config hooks.allownonascii true"
echo
exit 1
fi
exec git diff-index --check --cached $against --

169
test/fixtures/remotes/hooks/pre-rebase.sample vendored Executable file
View File

@ -0,0 +1,169 @@
#!/bin/sh
#
# Copyright (c) 2006, 2008 Junio C Hamano
#
# The "pre-rebase" hook is run just before "git-rebase" starts doing
# its job, and can prevent the command from running by exiting with
# non-zero status.
#
# The hook is called with the following parameters:
#
# $1 -- the upstream the series was forked from.
# $2 -- the branch being rebased (or empty when rebasing the current branch).
#
# This sample shows how to prevent topic branches that are already
# merged to 'next' branch from getting rebased, because allowing it
# would result in rebasing already published history.
publish=next
basebranch="$1"
if test "$#" = 2
then
topic="refs/heads/$2"
else
topic=`git symbolic-ref HEAD` ||
exit 0 ;# we do not interrupt rebasing detached HEAD
fi
case "$topic" in
refs/heads/??/*)
;;
*)
exit 0 ;# we do not interrupt others.
;;
esac
# Now we are dealing with a topic branch being rebased
# on top of master. Is it OK to rebase it?
# Does the topic really exist?
git show-ref -q "$topic" || {
echo >&2 "No such branch $topic"
exit 1
}
# Is topic fully merged to master?
not_in_master=`git-rev-list --pretty=oneline ^master "$topic"`
if test -z "$not_in_master"
then
echo >&2 "$topic is fully merged to master; better remove it."
exit 1 ;# we could allow it, but there is no point.
fi
# Is topic ever merged to next? If so you should not be rebasing it.
only_next_1=`git-rev-list ^master "^$topic" ${publish} | sort`
only_next_2=`git-rev-list ^master ${publish} | sort`
if test "$only_next_1" = "$only_next_2"
then
not_in_topic=`git-rev-list "^$topic" master`
if test -z "$not_in_topic"
then
echo >&2 "$topic is already up-to-date with master"
exit 1 ;# we could allow it, but there is no point.
else
exit 0
fi
else
not_in_next=`git-rev-list --pretty=oneline ^${publish} "$topic"`
perl -e '
my $topic = $ARGV[0];
my $msg = "* $topic has commits already merged to public branch:\n";
my (%not_in_next) = map {
/^([0-9a-f]+) /;
($1 => 1);
} split(/\n/, $ARGV[1]);
for my $elem (map {
/^([0-9a-f]+) (.*)$/;
[$1 => $2];
} split(/\n/, $ARGV[2])) {
if (!exists $not_in_next{$elem->[0]}) {
if ($msg) {
print STDERR $msg;
undef $msg;
}
print STDERR " $elem->[1]\n";
}
}
' "$topic" "$not_in_next" "$not_in_master"
exit 1
fi
exit 0
################################################################
This sample hook safeguards topic branches that have been
published from being rewound.
The workflow assumed here is:
* Once a topic branch forks from "master", "master" is never
merged into it again (either directly or indirectly).
* Once a topic branch is fully cooked and merged into "master",
it is deleted. If you need to build on top of it to correct
earlier mistakes, a new topic branch is created by forking at
the tip of the "master". This is not strictly necessary, but
it makes it easier to keep your history simple.
* Whenever you need to test or publish your changes to topic
branches, merge them into "next" branch.
The script, being an example, hardcodes the publish branch name
to be "next", but it is trivial to make it configurable via
$GIT_DIR/config mechanism.
With this workflow, you would want to know:
(1) ... if a topic branch has ever been merged to "next". Young
topic branches can have stupid mistakes you would rather
clean up before publishing, and things that have not been
merged into other branches can be easily rebased without
affecting other people. But once it is published, you would
not want to rewind it.
(2) ... if a topic branch has been fully merged to "master".
Then you can delete it. More importantly, you should not
build on top of it -- other people may already want to
change things related to the topic as patches against your
"master", so if you need further changes, it is better to
fork the topic (perhaps with the same name) afresh from the
tip of "master".
Let's look at this example:
o---o---o---o---o---o---o---o---o---o "next"
/ / / /
/ a---a---b A / /
/ / / /
/ / c---c---c---c B /
/ / / \ /
/ / / b---b C \ /
/ / / / \ /
---o---o---o---o---o---o---o---o---o---o---o "master"
A, B and C are topic branches.
* A has one fix since it was merged up to "next".
* B has finished. It has been fully merged up to "master" and "next",
and is ready to be deleted.
* C has not merged to "next" at all.
We would want to allow C to be rebased, refuse A, and encourage
B to be deleted.
To compute (1):
git-rev-list ^master ^topic next
git-rev-list ^master next
if these match, topic has not merged in next at all.
To compute (2):
git-rev-list master..topic
if this is empty, it is fully merged to "master".

View File

@ -0,0 +1,36 @@
#!/bin/sh
#
# An example hook script to prepare the commit log message.
# Called by git-commit with the name of the file that has the
# commit message, followed by the description of the commit
# message's source. The hook's purpose is to edit the commit
# message file. If the hook fails with a non-zero status,
# the commit is aborted.
#
# To enable this hook, rename this file to "prepare-commit-msg".
# This hook includes three examples. The first comments out the
# "Conflicts:" part of a merge commit.
#
# The second includes the output of "git diff --name-status -r"
# into the message, just before the "git status" output. It is
# commented because it doesn't cope with --amend or with squashed
# commits.
#
# The third example adds a Signed-off-by line to the message, that can
# still be edited. This is rarely a good idea.
case "$2,$3" in
merge,)
perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
# ,|template,)
# perl -i.bak -pe '
# print "\n" . `git diff --cached --name-status -r`
# if /^#/ && $first++ == 0' "$1" ;;
*) ;;
esac
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"

128
test/fixtures/remotes/hooks/update.sample vendored Executable file
View File

@ -0,0 +1,128 @@
#!/bin/sh
#
# An example hook script to blocks unannotated tags from entering.
# Called by git-receive-pack with arguments: refname sha1-old sha1-new
#
# To enable this hook, rename this file to "update".
#
# Config
# ------
# hooks.allowunannotated
# This boolean sets whether unannotated tags will be allowed into the
# repository. By default they won't be.
# hooks.allowdeletetag
# This boolean sets whether deleting tags will be allowed in the
# repository. By default they won't be.
# hooks.allowmodifytag
# This boolean sets whether a tag may be modified after creation. By default
# it won't be.
# hooks.allowdeletebranch
# This boolean sets whether deleting branches will be allowed in the
# repository. By default they won't be.
# hooks.denycreatebranch
# This boolean sets whether remotely creating branches will be denied
# in the repository. By default this is allowed.
#
# --- Command line
refname="$1"
oldrev="$2"
newrev="$3"
# --- Safety check
if [ -z "$GIT_DIR" ]; then
echo "Don't run this script from the command line." >&2
echo " (if you want, you could supply GIT_DIR then run" >&2
echo " $0 <ref> <oldrev> <newrev>)" >&2
exit 1
fi
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
exit 1
fi
# --- Config
allowunannotated=$(git config --bool hooks.allowunannotated)
allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
denycreatebranch=$(git config --bool hooks.denycreatebranch)
allowdeletetag=$(git config --bool hooks.allowdeletetag)
allowmodifytag=$(git config --bool hooks.allowmodifytag)
# check for no description
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
case "$projectdesc" in
"Unnamed repository"* | "")
echo "*** Project description file hasn't been set" >&2
exit 1
;;
esac
# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
zero="0000000000000000000000000000000000000000"
if [ "$newrev" = "$zero" ]; then
newrev_type=delete
else
newrev_type=$(git-cat-file -t $newrev)
fi
case "$refname","$newrev_type" in
refs/tags/*,commit)
# un-annotated tag
short_refname=${refname##refs/tags/}
if [ "$allowunannotated" != "true" ]; then
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
exit 1
fi
;;
refs/tags/*,delete)
# delete tag
if [ "$allowdeletetag" != "true" ]; then
echo "*** Deleting a tag is not allowed in this repository" >&2
exit 1
fi
;;
refs/tags/*,tag)
# annotated tag
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
then
echo "*** Tag '$refname' already exists." >&2
echo "*** Modifying a tag is not allowed in this repository." >&2
exit 1
fi
;;
refs/heads/*,commit)
# branch
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
echo "*** Creating a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/heads/*,delete)
# delete branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/remotes/*,commit)
# tracking branch
;;
refs/remotes/*,delete)
# delete tracking branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
exit 1
fi
;;
*)
# Anything else (is there anything else?)
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
exit 1
;;
esac
# --- Finished
exit 0

BIN
test/fixtures/remotes/index vendored Normal file

Binary file not shown.

6
test/fixtures/remotes/info/exclude vendored Normal file
View File

@ -0,0 +1,6 @@
# git-ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~

1
test/fixtures/remotes/logs/HEAD vendored Normal file
View File

@ -0,0 +1 @@
0000000000000000000000000000000000000000 bdd3996d38d885e18e5c5960df1c2c06e34d673f sentientwaffle <sentientwaffle@gmail.com> 1329101708 -0700 clone: from git@github.com:octocat/Spoon-Knife.git

View File

@ -0,0 +1 @@
0000000000000000000000000000000000000000 bdd3996d38d885e18e5c5960df1c2c06e34d673f sentientwaffle <sentientwaffle@gmail.com> 1329101708 -0700 clone: from git@github.com:octocat/Spoon-Knife.git

2
test/fixtures/remotes/packed-refs vendored Normal file
View File

@ -0,0 +1,2 @@
# pack-refs with: peeled
bdd3996d38d885e18e5c5960df1c2c06e34d673f refs/remotes/origin/master

View File

@ -0,0 +1 @@
bdd3996d38d885e18e5c5960df1c2c06e34d673f

Some files were not shown because too many files have changed in this diff Show More