mirror of
https://github.com/danog/gift.git
synced 2024-11-26 11:54:51 +01:00
initial commit
This commit is contained in:
commit
3ef68d9840
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
lib
|
||||
node_modules
|
0
.npmignore
Normal file
0
.npmignore
Normal file
20
LICENSE
Normal file
20
LICENSE
Normal 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
248
README.md
Normal 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
31
package.json
Normal 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
16
src/actor.coffee
Normal 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
17
src/blob.coffee
Normal 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
100
src/commit.coffee
Normal 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
61
src/diff.coffee
Normal 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
76
src/git.coffee
Normal 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
20
src/index.coffee
Normal 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
47
src/ref.coffee
Normal 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
224
src/repo.coffee
Normal 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
48
src/status.coffee
Normal 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
59
src/submodule.coffee
Normal 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
62
src/tag.coffee
Normal 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
103
src/tree.coffee
Normal 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
36
test/actor.test.coffee
Normal 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
45
test/blob.test.coffee
Normal 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
35
test/commit.test.coffee
Normal 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
98
test/diff.test.coffee
Normal 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
12
test/fixtures.coffee
Normal 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
1
test/fixtures/branched/COMMIT_EDITMSG
vendored
Normal file
@ -0,0 +1 @@
|
||||
add a sub dir
|
1
test/fixtures/branched/HEAD
vendored
Normal file
1
test/fixtures/branched/HEAD
vendored
Normal file
@ -0,0 +1 @@
|
||||
ref: refs/heads/master
|
5
test/fixtures/branched/config
vendored
Normal file
5
test/fixtures/branched/config
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
logallrefupdates = true
|
1
test/fixtures/branched/description
vendored
Normal file
1
test/fixtures/branched/description
vendored
Normal file
@ -0,0 +1 @@
|
||||
Unnamed repository; edit this file 'description' to name the repository.
|
15
test/fixtures/branched/hooks/applypatch-msg.sample
vendored
Executable file
15
test/fixtures/branched/hooks/applypatch-msg.sample
vendored
Executable 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/branched/hooks/commit-msg.sample
vendored
Executable file
24
test/fixtures/branched/hooks/commit-msg.sample
vendored
Executable 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
|
||||
}
|
8
test/fixtures/branched/hooks/post-commit.sample
vendored
Executable file
8
test/fixtures/branched/hooks/post-commit.sample
vendored
Executable 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
|
15
test/fixtures/branched/hooks/post-receive.sample
vendored
Executable file
15
test/fixtures/branched/hooks/post-receive.sample
vendored
Executable 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
|
8
test/fixtures/branched/hooks/post-update.sample
vendored
Executable file
8
test/fixtures/branched/hooks/post-update.sample
vendored
Executable 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
|
14
test/fixtures/branched/hooks/pre-applypatch.sample
vendored
Executable file
14
test/fixtures/branched/hooks/pre-applypatch.sample
vendored
Executable 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/branched/hooks/pre-commit.sample
vendored
Executable file
46
test/fixtures/branched/hooks/pre-commit.sample
vendored
Executable 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
169
test/fixtures/branched/hooks/pre-rebase.sample
vendored
Executable 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".
|
36
test/fixtures/branched/hooks/prepare-commit-msg.sample
vendored
Executable file
36
test/fixtures/branched/hooks/prepare-commit-msg.sample
vendored
Executable 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
128
test/fixtures/branched/hooks/update.sample
vendored
Executable 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
BIN
test/fixtures/branched/index
vendored
Normal file
Binary file not shown.
6
test/fixtures/branched/info/exclude
vendored
Normal file
6
test/fixtures/branched/info/exclude
vendored
Normal 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
7
test/fixtures/branched/logs/HEAD
vendored
Normal 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
|
2
test/fixtures/branched/logs/refs/heads/master
vendored
Normal file
2
test/fixtures/branched/logs/refs/heads/master
vendored
Normal 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
|
2
test/fixtures/branched/logs/refs/heads/something
vendored
Normal file
2
test/fixtures/branched/logs/refs/heads/something
vendored
Normal 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
|
BIN
test/fixtures/branched/objects/17/2b99dd464f6c9c101a987991fcc63491f08985
vendored
Normal file
BIN
test/fixtures/branched/objects/17/2b99dd464f6c9c101a987991fcc63491f08985
vendored
Normal file
Binary file not shown.
BIN
test/fixtures/branched/objects/6f/1de2421ce0427d9243bcd4ba7e38734cf96fe4
vendored
Normal file
BIN
test/fixtures/branched/objects/6f/1de2421ce0427d9243bcd4ba7e38734cf96fe4
vendored
Normal file
Binary file not shown.
BIN
test/fixtures/branched/objects/77/83d64e077617ab7b84fe9726f721e921b9623b
vendored
Normal file
BIN
test/fixtures/branched/objects/77/83d64e077617ab7b84fe9726f721e921b9623b
vendored
Normal file
Binary file not shown.
2
test/fixtures/branched/objects/91/3318e66e9beed3e89e9c402c1d6585ef3f7e6f
vendored
Normal file
2
test/fixtures/branched/objects/91/3318e66e9beed3e89e9c402c1d6585ef3f7e6f
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
x¥ŽÁ
|
||||
1D=÷+òJÚfÓDü•6muÁue·âïÛ«gÃ0ó]—eîàˆ}«lpY¤bj¬¢m’DlSeOÃ1JœÌ+mõÙ!#MU)[RƆÞ;á‰3…˜¹Æ,.{¯“Iï~_7ØÇhú¤Öοùz[Òü8éº\ÀZÏÁ¢í¸Úë_“J<E2809C>û;C™7óPxN
|
BIN
test/fixtures/branched/objects/9a/bc538b0dc8bf3974e04f3cb5d3f06240e8cef6
vendored
Normal file
BIN
test/fixtures/branched/objects/9a/bc538b0dc8bf3974e04f3cb5d3f06240e8cef6
vendored
Normal file
Binary file not shown.
BIN
test/fixtures/branched/objects/b0/45ec4b14c60f03329654266478b6e8b92b33c5
vendored
Normal file
BIN
test/fixtures/branched/objects/b0/45ec4b14c60f03329654266478b6e8b92b33c5
vendored
Normal file
Binary file not shown.
BIN
test/fixtures/branched/objects/b6/1b4728ef3cb2b3de0ec0421a54d170b6b7de13
vendored
Normal file
BIN
test/fixtures/branched/objects/b6/1b4728ef3cb2b3de0ec0421a54d170b6b7de13
vendored
Normal file
Binary file not shown.
BIN
test/fixtures/branched/objects/bd/502d58e9f0d51bd6c880994f778d0c896e4135
vendored
Normal file
BIN
test/fixtures/branched/objects/bd/502d58e9f0d51bd6c880994f778d0c896e4135
vendored
Normal file
Binary file not shown.
BIN
test/fixtures/branched/objects/c0/efd1cc406c54014067a7da9ab15c6a9c1bc714
vendored
Normal file
BIN
test/fixtures/branched/objects/c0/efd1cc406c54014067a7da9ab15c6a9c1bc714
vendored
Normal file
Binary file not shown.
BIN
test/fixtures/branched/objects/e4/ff69dd8f19d770e9731b4bc424ccb695f0b5ad
vendored
Normal file
BIN
test/fixtures/branched/objects/e4/ff69dd8f19d770e9731b4bc424ccb695f0b5ad
vendored
Normal file
Binary file not shown.
1
test/fixtures/branched/refs/heads/master
vendored
Normal file
1
test/fixtures/branched/refs/heads/master
vendored
Normal file
@ -0,0 +1 @@
|
||||
913318e66e9beed3e89e9c402c1d6585ef3f7e6f
|
1
test/fixtures/branched/refs/heads/something
vendored
Normal file
1
test/fixtures/branched/refs/heads/something
vendored
Normal file
@ -0,0 +1 @@
|
||||
7783d64e077617ab7b84fe9726f721e921b9623b
|
1
test/fixtures/checkout/COMMIT_EDITMSG
vendored
Normal file
1
test/fixtures/checkout/COMMIT_EDITMSG
vendored
Normal file
@ -0,0 +1 @@
|
||||
commit 1
|
1
test/fixtures/checkout/HEAD
vendored
Normal file
1
test/fixtures/checkout/HEAD
vendored
Normal file
@ -0,0 +1 @@
|
||||
ref: refs/heads/master
|
5
test/fixtures/checkout/config
vendored
Normal file
5
test/fixtures/checkout/config
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
logallrefupdates = true
|
1
test/fixtures/checkout/description
vendored
Normal file
1
test/fixtures/checkout/description
vendored
Normal file
@ -0,0 +1 @@
|
||||
Unnamed repository; edit this file 'description' to name the repository.
|
15
test/fixtures/checkout/hooks/applypatch-msg.sample
vendored
Executable file
15
test/fixtures/checkout/hooks/applypatch-msg.sample
vendored
Executable 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/checkout/hooks/commit-msg.sample
vendored
Executable file
24
test/fixtures/checkout/hooks/commit-msg.sample
vendored
Executable 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
|
||||
}
|
8
test/fixtures/checkout/hooks/post-commit.sample
vendored
Executable file
8
test/fixtures/checkout/hooks/post-commit.sample
vendored
Executable 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
|
15
test/fixtures/checkout/hooks/post-receive.sample
vendored
Executable file
15
test/fixtures/checkout/hooks/post-receive.sample
vendored
Executable 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
|
8
test/fixtures/checkout/hooks/post-update.sample
vendored
Executable file
8
test/fixtures/checkout/hooks/post-update.sample
vendored
Executable 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
|
14
test/fixtures/checkout/hooks/pre-applypatch.sample
vendored
Executable file
14
test/fixtures/checkout/hooks/pre-applypatch.sample
vendored
Executable 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/checkout/hooks/pre-commit.sample
vendored
Executable file
46
test/fixtures/checkout/hooks/pre-commit.sample
vendored
Executable 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
169
test/fixtures/checkout/hooks/pre-rebase.sample
vendored
Executable 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".
|
36
test/fixtures/checkout/hooks/prepare-commit-msg.sample
vendored
Executable file
36
test/fixtures/checkout/hooks/prepare-commit-msg.sample
vendored
Executable 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
128
test/fixtures/checkout/hooks/update.sample
vendored
Executable 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
BIN
test/fixtures/checkout/index
vendored
Normal file
Binary file not shown.
6
test/fixtures/checkout/info/exclude
vendored
Normal file
6
test/fixtures/checkout/info/exclude
vendored
Normal 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
100
test/fixtures/checkout/logs/HEAD
vendored
Normal 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
|
1
test/fixtures/checkout/logs/refs/heads/b2
vendored
Normal file
1
test/fixtures/checkout/logs/refs/heads/b2
vendored
Normal file
@ -0,0 +1 @@
|
||||
0000000000000000000000000000000000000000 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248175 -0700 branch: Created from HEAD
|
1
test/fixtures/checkout/logs/refs/heads/b3
vendored
Normal file
1
test/fixtures/checkout/logs/refs/heads/b3
vendored
Normal file
@ -0,0 +1 @@
|
||||
0000000000000000000000000000000000000000 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248189 -0700 branch: Created from HEAD
|
1
test/fixtures/checkout/logs/refs/heads/master
vendored
Normal file
1
test/fixtures/checkout/logs/refs/heads/master
vendored
Normal file
@ -0,0 +1 @@
|
||||
0000000000000000000000000000000000000000 5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa sentientwaffle <sentientwaffle@gmail.com> 1329248161 -0700 commit (initial): commit 1
|
BIN
test/fixtures/checkout/objects/5d/0a23d3d71875e5abe637a1b7b3b9ea050f16aa
vendored
Normal file
BIN
test/fixtures/checkout/objects/5d/0a23d3d71875e5abe637a1b7b3b9ea050f16aa
vendored
Normal file
Binary file not shown.
BIN
test/fixtures/checkout/objects/e5/fa16f39fe47d5562b74c4f5912d8ef07dd126a
vendored
Normal file
BIN
test/fixtures/checkout/objects/e5/fa16f39fe47d5562b74c4f5912d8ef07dd126a
vendored
Normal file
Binary file not shown.
BIN
test/fixtures/checkout/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
vendored
Normal file
BIN
test/fixtures/checkout/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
vendored
Normal file
Binary file not shown.
1
test/fixtures/checkout/refs/heads/b2
vendored
Normal file
1
test/fixtures/checkout/refs/heads/b2
vendored
Normal file
@ -0,0 +1 @@
|
||||
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa
|
1
test/fixtures/checkout/refs/heads/b3
vendored
Normal file
1
test/fixtures/checkout/refs/heads/b3
vendored
Normal file
@ -0,0 +1 @@
|
||||
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa
|
1
test/fixtures/checkout/refs/heads/master
vendored
Normal file
1
test/fixtures/checkout/refs/heads/master
vendored
Normal file
@ -0,0 +1 @@
|
||||
5d0a23d3d71875e5abe637a1b7b3b9ea050f16aa
|
1
test/fixtures/remotes/HEAD
vendored
Normal file
1
test/fixtures/remotes/HEAD
vendored
Normal file
@ -0,0 +1 @@
|
||||
ref: refs/heads/master
|
11
test/fixtures/remotes/config
vendored
Normal file
11
test/fixtures/remotes/config
vendored
Normal 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
1
test/fixtures/remotes/description
vendored
Normal file
@ -0,0 +1 @@
|
||||
Unnamed repository; edit this file 'description' to name the repository.
|
15
test/fixtures/remotes/hooks/applypatch-msg.sample
vendored
Executable file
15
test/fixtures/remotes/hooks/applypatch-msg.sample
vendored
Executable 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
24
test/fixtures/remotes/hooks/commit-msg.sample
vendored
Executable 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
|
||||
}
|
8
test/fixtures/remotes/hooks/post-commit.sample
vendored
Executable file
8
test/fixtures/remotes/hooks/post-commit.sample
vendored
Executable 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
|
15
test/fixtures/remotes/hooks/post-receive.sample
vendored
Executable file
15
test/fixtures/remotes/hooks/post-receive.sample
vendored
Executable 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
|
8
test/fixtures/remotes/hooks/post-update.sample
vendored
Executable file
8
test/fixtures/remotes/hooks/post-update.sample
vendored
Executable 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
|
14
test/fixtures/remotes/hooks/pre-applypatch.sample
vendored
Executable file
14
test/fixtures/remotes/hooks/pre-applypatch.sample
vendored
Executable 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
46
test/fixtures/remotes/hooks/pre-commit.sample
vendored
Executable 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
169
test/fixtures/remotes/hooks/pre-rebase.sample
vendored
Executable 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".
|
36
test/fixtures/remotes/hooks/prepare-commit-msg.sample
vendored
Executable file
36
test/fixtures/remotes/hooks/prepare-commit-msg.sample
vendored
Executable 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
128
test/fixtures/remotes/hooks/update.sample
vendored
Executable 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
BIN
test/fixtures/remotes/index
vendored
Normal file
Binary file not shown.
6
test/fixtures/remotes/info/exclude
vendored
Normal file
6
test/fixtures/remotes/info/exclude
vendored
Normal 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
1
test/fixtures/remotes/logs/HEAD
vendored
Normal file
@ -0,0 +1 @@
|
||||
0000000000000000000000000000000000000000 bdd3996d38d885e18e5c5960df1c2c06e34d673f sentientwaffle <sentientwaffle@gmail.com> 1329101708 -0700 clone: from git@github.com:octocat/Spoon-Knife.git
|
1
test/fixtures/remotes/logs/refs/heads/master
vendored
Normal file
1
test/fixtures/remotes/logs/refs/heads/master
vendored
Normal file
@ -0,0 +1 @@
|
||||
0000000000000000000000000000000000000000 bdd3996d38d885e18e5c5960df1c2c06e34d673f sentientwaffle <sentientwaffle@gmail.com> 1329101708 -0700 clone: from git@github.com:octocat/Spoon-Knife.git
|
BIN
test/fixtures/remotes/objects/pack/pack-3f24024466408b565d66ecd5902c84ec2362e513.idx
vendored
Normal file
BIN
test/fixtures/remotes/objects/pack/pack-3f24024466408b565d66ecd5902c84ec2362e513.idx
vendored
Normal file
Binary file not shown.
BIN
test/fixtures/remotes/objects/pack/pack-3f24024466408b565d66ecd5902c84ec2362e513.pack
vendored
Normal file
BIN
test/fixtures/remotes/objects/pack/pack-3f24024466408b565d66ecd5902c84ec2362e513.pack
vendored
Normal file
Binary file not shown.
2
test/fixtures/remotes/packed-refs
vendored
Normal file
2
test/fixtures/remotes/packed-refs
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# pack-refs with: peeled
|
||||
bdd3996d38d885e18e5c5960df1c2c06e34d673f refs/remotes/origin/master
|
1
test/fixtures/remotes/refs/heads/master
vendored
Normal file
1
test/fixtures/remotes/refs/heads/master
vendored
Normal file
@ -0,0 +1 @@
|
||||
bdd3996d38d885e18e5c5960df1c2c06e34d673f
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user