| |   |
| 29 | 29 | end |
| 30 | 30 | |
| 31 | 31 | def self.create_git_repository(path) |
| 32 | | git_backend.create(full_path_from_partial_path(path)) |
| 32 | full_path = full_path_from_partial_path(path) |
| 33 | git_backend.create(full_path) |
| 34 | |
| 35 | hooks = File.join(GitoriousConfig["repository_base_path"], ".hooks") |
| 36 | Dir.chdir(full_path) do |
| 37 | hooks_base_path = File.expand_path(File.join(File.dirname(__FILE__), "../../data/hooks")) # FIXME: the hooks are in GITORIOUS_ROOT/data/hooks |
| 38 | |
| 39 | if not File.symlink?(hooks) |
| 40 | if not File.exist?(hooks) |
| 41 | FileUtils.ln_s(hooks_base_path, hooks) # Create symlink |
| 42 | end |
| 43 | elsif File.expand_path(File.readlink(hooks)) != hooks_base_path |
| 44 | FileUtils.ln_sf(hooks_base_path, hooks) # Fixup symlink |
| 45 | end |
| 46 | end |
| 47 | |
| 48 | local_hooks = File.join(full_path, "hooks") |
| 49 | unless File.exist?(local_hooks) |
| 50 | target_path = Pathname.new(hooks).relative_path_from(Pathname.new(full_path)) |
| 51 | Dir.chdir(full_path) do |
| 52 | FileUtils.ln_s(target_path, "hooks") |
| 53 | end |
| 54 | end |
| 55 | |
| 56 | File.open(File.join(full_path, "description"), "w") do |file| |
| 57 | file << path.sub(/\.git$/, "") << "\n" |
| 58 | end |
| 33 | 59 | end |
| 34 | 60 | |
| 35 | 61 | def self.clone_git_repository(target_path, source_path) |
| toggle raw diff |
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -29,7 +29,33 @@ class Repository < ActiveRecord::Base
end
def self.create_git_repository(path)
- git_backend.create(full_path_from_partial_path(path))
+ full_path = full_path_from_partial_path(path)
+ git_backend.create(full_path)
+
+ hooks = File.join(GitoriousConfig["repository_base_path"], ".hooks")
+ Dir.chdir(full_path) do
+ hooks_base_path = File.expand_path(File.join(File.dirname(__FILE__), "../../data/hooks")) # FIXME: the hooks are in GITORIOUS_ROOT/data/hooks
+
+ if not File.symlink?(hooks)
+ if not File.exist?(hooks)
+ FileUtils.ln_s(hooks_base_path, hooks) # Create symlink
+ end
+ elsif File.expand_path(File.readlink(hooks)) != hooks_base_path
+ FileUtils.ln_sf(hooks_base_path, hooks) # Fixup symlink
+ end
+ end
+
+ local_hooks = File.join(full_path, "hooks")
+ unless File.exist?(local_hooks)
+ target_path = Pathname.new(hooks).relative_path_from(Pathname.new(full_path))
+ Dir.chdir(full_path) do
+ FileUtils.ln_s(target_path, "hooks")
+ end
+ end
+
+ File.open(File.join(full_path, "description"), "w") do |file|
+ file << path.sub(/\.git$/, "") << "\n"
+ end
end
def self.clone_git_repository(target_path, source_path) |
| |   |
| 0 | | module Grit |
| 1 | | class << self; attr_accessor :debug end |
| 2 | | # self.debug = true |
| 3 | | class Git |
| 4 | | undef_method :clone |
| 5 | | |
| 6 | | class << self |
| 7 | | attr_accessor :git_binary |
| 8 | | end |
| 9 | | |
| 10 | | self.git_binary = "/usr/bin/env git" |
| 11 | | |
| 12 | | attr_accessor :git_dir |
| 13 | | |
| 14 | | def initialize(git_dir) |
| 15 | | self.git_dir = git_dir |
| 16 | | end |
| 17 | | |
| 18 | | def execute(command) |
| 19 | | `#{command}` |
| 20 | | end |
| 21 | | |
| 22 | | # Run the given git command with the specified arguments and return |
| 23 | | # the result as a String |
| 24 | | # +cmd+ is the command |
| 25 | | # +options+ is a hash of Ruby style options |
| 26 | | # +args+ is the list of arguments (to be joined by spaces) |
| 27 | | # |
| 28 | | # Examples |
| 29 | | # git.rev_list({:max_count => 10, :header => true}, "master") |
| 30 | | # |
| 31 | | # Returns String |
| 32 | | def method_missing(cmd, options = {}, *args) |
| 33 | | opt_args = transform_options(options) |
| 34 | | ext_args = args.map { |a| (a == '--' or a =~ /^\s*\|/) ? a : "'#{e(a)}'" } |
| 35 | | |
| 36 | | call = "#{Git.git_binary} --git-dir='#{self.git_dir}' #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}" |
| 37 | | puts call if Grit.debug |
| 38 | | response = execute(call) |
| 39 | | puts response if Grit.debug |
| 40 | | response |
| 41 | | end |
| 42 | | |
| 43 | | def shell_escape(str) |
| 44 | | str.to_s.gsub("'", "\\\\'") |
| 45 | | end |
| 46 | | alias_method :e, :shell_escape |
| 47 | | |
| 48 | | # Transform Ruby style options into git command line options |
| 49 | | # +options+ is a hash of Ruby style options |
| 50 | | # |
| 51 | | # Returns String[] |
| 52 | | # e.g. ["--max-count=10", "--header"] |
| 53 | | def transform_options(options) |
| 54 | | args = [] |
| 55 | | options.keys.each do |opt| |
| 56 | | if opt.to_s.size == 1 |
| 57 | | if options[opt] == true |
| 58 | | args << "-#{opt}" |
| 59 | | else |
| 60 | | val = options.delete(opt) |
| 61 | | args << "-#{opt.to_s} '#{e(val)}'" |
| 62 | | end |
| 63 | | else |
| 64 | | if options[opt] == true |
| 65 | | args << "--#{opt.to_s.gsub(/_/, '-')}" |
| 66 | | else |
| 67 | | val = options.delete(opt) |
| 68 | | args << "--#{opt.to_s.gsub(/_/, '-')}='#{e(val)}'" |
| 69 | | end |
| 70 | | end |
| 71 | | end |
| 72 | | args |
| 73 | | end |
| 74 | | end # Git |
| 75 | | |
| 76 | | end # Grit |
| toggle raw diff |
--- a/data/git-template/hooks/git.rb
+++ /dev/null
@@ -1,77 +0,0 @@
-module Grit
- class << self; attr_accessor :debug end
-# self.debug = true
- class Git
- undef_method :clone
-
- class << self
- attr_accessor :git_binary
- end
-
- self.git_binary = "/usr/bin/env git"
-
- attr_accessor :git_dir
-
- def initialize(git_dir)
- self.git_dir = git_dir
- end
-
- def execute(command)
- `#{command}`
- end
-
- # Run the given git command with the specified arguments and return
- # the result as a String
- # +cmd+ is the command
- # +options+ is a hash of Ruby style options
- # +args+ is the list of arguments (to be joined by spaces)
- #
- # Examples
- # git.rev_list({:max_count => 10, :header => true}, "master")
- #
- # Returns String
- def method_missing(cmd, options = {}, *args)
- opt_args = transform_options(options)
- ext_args = args.map { |a| (a == '--' or a =~ /^\s*\|/) ? a : "'#{e(a)}'" }
-
- call = "#{Git.git_binary} --git-dir='#{self.git_dir}' #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}"
- puts call if Grit.debug
- response = execute(call)
- puts response if Grit.debug
- response
- end
-
- def shell_escape(str)
- str.to_s.gsub("'", "\\\\'")
- end
- alias_method :e, :shell_escape
-
- # Transform Ruby style options into git command line options
- # +options+ is a hash of Ruby style options
- #
- # Returns String[]
- # e.g. ["--max-count=10", "--header"]
- def transform_options(options)
- args = []
- options.keys.each do |opt|
- if opt.to_s.size == 1
- if options[opt] == true
- args << "-#{opt}"
- else
- val = options.delete(opt)
- args << "-#{opt.to_s} '#{e(val)}'"
- end
- else
- if options[opt] == true
- args << "--#{opt.to_s.gsub(/_/, '-')}"
- else
- val = options.delete(opt)
- args << "--#{opt.to_s.gsub(/_/, '-')}='#{e(val)}'"
- end
- end
- end
- args
- end
- end # Git
-
-end # Grit |
| |   |
| 0 | | #!/usr/bin/env ruby |
| 1 | | |
| 2 | | $: << File.dirname(__FILE__) |
| 3 | | require 'git' |
| 4 | | require 'date' |
| 5 | | |
| 6 | | gitdir = File.expand_path(File.join(File.dirname(__FILE__), "..")) |
| 7 | | slug = File.basename(gitdir) |
| 8 | | |
| 9 | | if slug == "mainline.git" |
| 10 | | slug = File.basename(File.expand_path(File.join(gitdir, ".."))) |
| 11 | | end |
| 12 | | |
| 13 | | git = Grit::Git.new(gitdir) |
| 14 | | |
| 15 | | while line = gets |
| 16 | | oldrev, newrev, revname = line.split(" ") |
| 17 | | current_rev = newrev |
| 18 | | newtype = oldtype = current_rev_type = "commit" |
| 19 | | |
| 20 | | action = :create |
| 21 | | if oldrev =~ /^0+$/ |
| 22 | | action = :create |
| 23 | | else |
| 24 | | if newrev =~ /^0+$/ |
| 25 | | action = :delete |
| 26 | | else |
| 27 | | action = :update |
| 28 | | end |
| 29 | | end |
| 30 | | |
| 31 | | if action != :create |
| 32 | | newtype = git.cat_file({:t => true}, newrev) |
| 33 | | oldtype = git.cat_file({:t => true}, oldrev) |
| 34 | | end |
| 35 | | |
| 36 | | if action == :delete |
| 37 | | current_rev = oldrev |
| 38 | | current_rev_type = oldtype |
| 39 | | end |
| 40 | | |
| 41 | | path, type, name = revname.split("/") |
| 42 | | |
| 43 | | info = git.show({ :pretty => "format:author: %cn%nemail: %ce%ndate: %cd%nmessage: %s", :s => true}, current_rev ) |
| 44 | | |
| 45 | | hash = {} |
| 46 | | info.each { |line| |
| 47 | | if line =~ /(\w+):\s(.*)$/ |
| 48 | | key = $1.to_sym |
| 49 | | value = $2 |
| 50 | | |
| 51 | | value = Date.parse(value) if key == :date |
| 52 | | |
| 53 | | hash[key] = value |
| 54 | | end |
| 55 | | } |
| 56 | | |
| 57 | | puts "#{hash[:author]}: #{action} #{current_rev_type} on #{slug} [#{hash[:date]}]" |
| 58 | | puts " #{hash[:message]}" |
| 59 | | |
| 60 | | end |
| 61 | | |
| 62 | | puts "=> Thanks!" |
| 63 | | |
| toggle raw diff |
--- a/data/git-template/hooks/post-receive
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/usr/bin/env ruby
-
-$: << File.dirname(__FILE__)
-require 'git'
-require 'date'
-
-gitdir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
-slug = File.basename(gitdir)
-
-if slug == "mainline.git"
- slug = File.basename(File.expand_path(File.join(gitdir, "..")))
-end
-
-git = Grit::Git.new(gitdir)
-
-while line = gets
- oldrev, newrev, revname = line.split(" ")
- current_rev = newrev
- newtype = oldtype = current_rev_type = "commit"
-
- action = :create
- if oldrev =~ /^0+$/
- action = :create
- else
- if newrev =~ /^0+$/
- action = :delete
- else
- action = :update
- end
- end
-
- if action != :create
- newtype = git.cat_file({:t => true}, newrev)
- oldtype = git.cat_file({:t => true}, oldrev)
- end
-
- if action == :delete
- current_rev = oldrev
- current_rev_type = oldtype
- end
-
- path, type, name = revname.split("/")
-
- info = git.show({ :pretty => "format:author: %cn%nemail: %ce%ndate: %cd%nmessage: %s", :s => true}, current_rev )
-
- hash = {}
- info.each { |line|
- if line =~ /(\w+):\s(.*)$/
- key = $1.to_sym
- value = $2
-
- value = Date.parse(value) if key == :date
-
- hash[key] = value
- end
- }
-
- puts "#{hash[:author]}: #{action} #{current_rev_type} on #{slug} [#{hash[:date]}]"
- puts " #{hash[:message]}"
-
-end
-
-puts "=> Thanks!"
- |
| |   |
| 0 | | #!/bin/sh |
| 1 | | # |
| 2 | | # An example hook script to verify what is about to be committed. |
| 3 | | # Called by git-commit with no arguments. The hook should |
| 4 | | # exit with non-zero status after issuing an appropriate message if |
| 5 | | # it wants to stop the commit. |
| 6 | | # |
| 7 | | # To enable this hook, make this file executable. |
| 8 | | |
| 9 | | # This is slightly modified from Andrew Morton's Perfect Patch. |
| 10 | | # Lines you introduce should not have trailing whitespace. |
| 11 | | # Also check for an indentation that has SP before a TAB. |
| 12 | | |
| 13 | | if git-rev-parse --verify HEAD 2>/dev/null |
| 14 | | then |
| 15 | | git-diff-index -p -M --cached HEAD |
| 16 | | else |
| 17 | | # NEEDSWORK: we should produce a diff with an empty tree here |
| 18 | | # if we want to do the same verification for the initial import. |
| 19 | | : |
| 20 | | fi | |
| 21 | | perl -e ' |
| 22 | | my $found_bad = 0; |
| 23 | | my $filename; |
| 24 | | my $reported_filename = ""; |
| 25 | | my $lineno; |
| 26 | | sub bad_line { |
| 27 | | my ($why, $line) = @_; |
| 28 | | if (!$found_bad) { |
| 29 | | print STDERR "*\n"; |
| 30 | | print STDERR "* You have some suspicious patch lines:\n"; |
| 31 | | print STDERR "*\n"; |
| 32 | | $found_bad = 1; |
| 33 | | } |
| 34 | | if ($reported_filename ne $filename) { |
| 35 | | print STDERR "* In $filename\n"; |
| 36 | | $reported_filename = $filename; |
| 37 | | } |
| 38 | | print STDERR "* $why (line $lineno)\n"; |
| 39 | | print STDERR "$filename:$lineno:$line\n"; |
| 40 | | } |
| 41 | | while (<>) { |
| 42 | | if (m|^diff --git a/(.*) b/\1$|) { |
| 43 | | $filename = $1; |
| 44 | | next; |
| 45 | | } |
| 46 | | if (/^@@ -\S+ \+(\d+)/) { |
| 47 | | $lineno = $1 - 1; |
| 48 | | next; |
| 49 | | } |
| 50 | | if (/^ /) { |
| 51 | | $lineno++; |
| 52 | | next; |
| 53 | | } |
| 54 | | if (s/^\+//) { |
| 55 | | $lineno++; |
| 56 | | chomp; |
| 57 | | if (/\s$/) { |
| 58 | | bad_line("trailing whitespace", $_); |
| 59 | | } |
| 60 | | if (/^\s* /) { |
| 61 | | bad_line("indent SP followed by a TAB", $_); |
| 62 | | } |
| 63 | | if (/^(?:[<>=]){7}/) { |
| 64 | | bad_line("unresolved merge conflict", $_); |
| 65 | | } |
| 66 | | } |
| 67 | | } |
| 68 | | exit($found_bad); |
| 69 | | ' |
| 70 | | |
| toggle raw diff |
--- a/data/git-template/hooks/pre-commit
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/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, make this file executable.
-
-# This is slightly modified from Andrew Morton's Perfect Patch.
-# Lines you introduce should not have trailing whitespace.
-# Also check for an indentation that has SP before a TAB.
-
-if git-rev-parse --verify HEAD 2>/dev/null
-then
- git-diff-index -p -M --cached HEAD
-else
- # NEEDSWORK: we should produce a diff with an empty tree here
- # if we want to do the same verification for the initial import.
- :
-fi |
-perl -e '
- my $found_bad = 0;
- my $filename;
- my $reported_filename = "";
- my $lineno;
- sub bad_line {
- my ($why, $line) = @_;
- if (!$found_bad) {
- print STDERR "*\n";
- print STDERR "* You have some suspicious patch lines:\n";
- print STDERR "*\n";
- $found_bad = 1;
- }
- if ($reported_filename ne $filename) {
- print STDERR "* In $filename\n";
- $reported_filename = $filename;
- }
- print STDERR "* $why (line $lineno)\n";
- print STDERR "$filename:$lineno:$line\n";
- }
- while (<>) {
- if (m|^diff --git a/(.*) b/\1$|) {
- $filename = $1;
- next;
- }
- if (/^@@ -\S+ \+(\d+)/) {
- $lineno = $1 - 1;
- next;
- }
- if (/^ /) {
- $lineno++;
- next;
- }
- if (s/^\+//) {
- $lineno++;
- chomp;
- if (/\s$/) {
- bad_line("trailing whitespace", $_);
- }
- if (/^\s* /) {
- bad_line("indent SP followed by a TAB", $_);
- }
- if (/^(?:[<>=]){7}/) {
- bad_line("unresolved merge conflict", $_);
- }
- }
- }
- exit($found_bad);
-'
- |
| |   |
| 0 | | #!/bin/sh |
| 1 | | # |
| 2 | | # Copyright (c) 2006 Junio C Hamano |
| 3 | | # |
| 4 | | |
| 5 | | publish=next |
| 6 | | basebranch="$1" |
| 7 | | if test "$#" = 2 |
| 8 | | then |
| 9 | | topic="refs/heads/$2" |
| 10 | | else |
| 11 | | topic=`git symbolic-ref HEAD` |
| 12 | | fi |
| 13 | | |
| 14 | | case "$basebranch,$topic" in |
| 15 | | master,refs/heads/??/*) |
| 16 | | ;; |
| 17 | | *) |
| 18 | | exit 0 ;# we do not interrupt others. |
| 19 | | ;; |
| 20 | | esac |
| 21 | | |
| 22 | | # Now we are dealing with a topic branch being rebased |
| 23 | | # on top of master. Is it OK to rebase it? |
| 24 | | |
| 25 | | # Is topic fully merged to master? |
| 26 | | not_in_master=`git-rev-list --pretty=oneline ^master "$topic"` |
| 27 | | if test -z "$not_in_master" |
| 28 | | then |
| 29 | | echo >&2 "$topic is fully merged to master; better remove it." |
| 30 | | exit 1 ;# we could allow it, but there is no point. |
| 31 | | fi |
| 32 | | |
| 33 | | # Is topic ever merged to next? If so you should not be rebasing it. |
| 34 | | only_next_1=`git-rev-list ^master "^$topic" ${publish} | sort` |
| 35 | | only_next_2=`git-rev-list ^master ${publish} | sort` |
| 36 | | if test "$only_next_1" = "$only_next_2" |
| 37 | | then |
| 38 | | not_in_topic=`git-rev-list "^$topic" master` |
| 39 | | if test -z "$not_in_topic" |
| 40 | | then |
| 41 | | echo >&2 "$topic is already up-to-date with master" |
| 42 | | exit 1 ;# we could allow it, but there is no point. |
| 43 | | else |
| 44 | | exit 0 |
| 45 | | fi |
| 46 | | else |
| 47 | | not_in_next=`git-rev-list --pretty=oneline ^${publish} "$topic"` |
| 48 | | perl -e ' |
| 49 | | my $topic = $ARGV[0]; |
| 50 | | my $msg = "* $topic has commits already merged to public branch:\n"; |
| 51 | | my (%not_in_next) = map { |
| 52 | | /^([0-9a-f]+) /; |
| 53 | | ($1 => 1); |
| 54 | | } split(/\n/, $ARGV[1]); |
| 55 | | for my $elem (map { |
| 56 | | /^([0-9a-f]+) (.*)$/; |
| 57 | | [$1 => $2]; |
| 58 | | } split(/\n/, $ARGV[2])) { |
| 59 | | if (!exists $not_in_next{$elem->[0]}) { |
| 60 | | if ($msg) { |
| 61 | | print STDERR $msg; |
| 62 | | undef $msg; |
| 63 | | } |
| 64 | | print STDERR " $elem->[1]\n"; |
| 65 | | } |
| 66 | | } |
| 67 | | ' "$topic" "$not_in_next" "$not_in_master" |
| 68 | | exit 1 |
| 69 | | fi |
| 70 | | |
| 71 | | exit 0 |
| 72 | | |
| 73 | | ################################################################ |
| 74 | | |
| 75 | | This sample hook safeguards topic branches that have been |
| 76 | | published from being rewound. |
| 77 | | |
| 78 | | The workflow assumed here is: |
| 79 | | |
| 80 | | * Once a topic branch forks from "master", "master" is never |
| 81 | | merged into it again (either directly or indirectly). |
| 82 | | |
| 83 | | * Once a topic branch is fully cooked and merged into "master", |
| 84 | | it is deleted. If you need to build on top of it to correct |
| 85 | | earlier mistakes, a new topic branch is created by forking at |
| 86 | | the tip of the "master". This is not strictly necessary, but |
| 87 | | it makes it easier to keep your history simple. |
| 88 | | |
| 89 | | * Whenever you need to test or publish your changes to topic |
| 90 | | branches, merge them into "next" branch. |
| 91 | | |
| 92 | | The script, being an example, hardcodes the publish branch name |
| 93 | | to be "next", but it is trivial to make it configurable via |
| 94 | | $GIT_DIR/config mechanism. |
| 95 | | |
| 96 | | With this workflow, you would want to know: |
| 97 | | |
| 98 | | (1) ... if a topic branch has ever been merged to "next". Young |
| 99 | | topic branches can have stupid mistakes you would rather |
| 100 | | clean up before publishing, and things that have not been |
| 101 | | merged into other branches can be easily rebased without |
| 102 | | affecting other people. But once it is published, you would |
| 103 | | not want to rewind it. |
| 104 | | |
| 105 | | (2) ... if a topic branch has been fully merged to "master". |
| 106 | | Then you can delete it. More importantly, you should not |
| 107 | | build on top of it -- other people may already want to |
| 108 | | change things related to the topic as patches against your |
| 109 | | "master", so if you need further changes, it is better to |
| 110 | | fork the topic (perhaps with the same name) afresh from the |
| 111 | | tip of "master". |
| 112 | | |
| 113 | | Let's look at this example: |
| 114 | | |
| 115 | | o---o---o---o---o---o---o---o---o---o "next" |
| 116 | | / / / / |
| 117 | | / a---a---b A / / |
| 118 | | / / / / |
| 119 | | / / c---c---c---c B / |
| 120 | | / / / \ / |
| 121 | | / / / b---b C \ / |
| 122 | | / / / / \ / |
| 123 | | ---o---o---o---o---o---o---o---o---o---o---o "master" |
| 124 | | |
| 125 | | |
| 126 | | A, B and C are topic branches. |
| 127 | | |
| 128 | | * A has one fix since it was merged up to "next". |
| 129 | | |
| 130 | | * B has finished. It has been fully merged up to "master" and "next", |
| 131 | | and is ready to be deleted. |
| 132 | | |
| 133 | | * C has not merged to "next" at all. |
| 134 | | |
| 135 | | We would want to allow C to be rebased, refuse A, and encourage |
| 136 | | B to be deleted. |
| 137 | | |
| 138 | | To compute (1): |
| 139 | | |
| 140 | | git-rev-list ^master ^topic next |
| 141 | | git-rev-list ^master next |
| 142 | | |
| 143 | | if these match, topic has not merged in next at all. |
| 144 | | |
| 145 | | To compute (2): |
| 146 | | |
| 147 | | git-rev-list master..topic |
| 148 | | |
| 149 | | if this is empty, it is fully merged to "master". |
| toggle raw diff |
--- a/data/git-template/hooks/pre-rebase
+++ /dev/null
@@ -1,150 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2006 Junio C Hamano
-#
-
-publish=next
-basebranch="$1"
-if test "$#" = 2
-then
- topic="refs/heads/$2"
-else
- topic=`git symbolic-ref HEAD`
-fi
-
-case "$basebranch,$topic" in
-master,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?
-
-# 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". |
| |   |
| 0 | | #!/bin/sh |
| 1 | | # |
| 2 | | # An example hook script to blocks unannotated tags from entering. |
| 3 | | # Called by git-receive-pack with arguments: refname sha1-old sha1-new |
| 4 | | # |
| 5 | | # To enable this hook, make this file executable by "chmod +x update". |
| 6 | | # |
| 7 | | # Config |
| 8 | | # ------ |
| 9 | | # hooks.allowunannotated |
| 10 | | # This boolean sets whether unannotated tags will be allowed into the |
| 11 | | # repository. By default they won't be. |
| 12 | | # |
| 13 | | |
| 14 | | # --- Command line |
| 15 | | refname="$1" |
| 16 | | oldrev="$2" |
| 17 | | newrev="$3" |
| 18 | | |
| 19 | | # --- Safety check |
| 20 | | if [ -z "$GIT_DIR" ]; then |
| 21 | | echo "Don't run this script from the command line." >&2 |
| 22 | | echo " (if you want, you could supply GIT_DIR then run" >&2 |
| 23 | | echo " $0 <ref> <oldrev> <newrev>)" >&2 |
| 24 | | exit 1 |
| 25 | | fi |
| 26 | | |
| 27 | | if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then |
| 28 | | echo "Usage: $0 <ref> <oldrev> <newrev>" >&2 |
| 29 | | exit 1 |
| 30 | | fi |
| 31 | | |
| 32 | | # --- Config |
| 33 | | allowunannotated=$(git-repo-config --bool hooks.allowunannotated) |
| 34 | | |
| 35 | | # check for no description |
| 36 | | projectdesc=$(sed -e '1p' "$GIT_DIR/description") |
| 37 | | if [ -z "$projectdesc" -o "$projectdesc" = "Unnamed repository; edit this file to name it for gitweb" ]; then |
| 38 | | echo "*** Project description file hasn't been set" >&2 |
| 39 | | exit 1 |
| 40 | | fi |
| 41 | | |
| 42 | | # --- Check types |
| 43 | | # if $newrev is 0000...0000, it's a commit to delete a branch |
| 44 | | if [ -z "${newrev##0*}" ]; then |
| 45 | | newrev_type=commit |
| 46 | | else |
| 47 | | newrev_type=$(git-cat-file -t $newrev) |
| 48 | | fi |
| 49 | | |
| 50 | | case "$refname","$newrev_type" in |
| 51 | | refs/tags/*,commit) |
| 52 | | # un-annotated tag |
| 53 | | short_refname=${refname##refs/tags/} |
| 54 | | if [ "$allowunannotated" != "true" ]; then |
| 55 | | echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 |
| 56 | | echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 |
| 57 | | exit 1 |
| 58 | | fi |
| 59 | | ;; |
| 60 | | refs/tags/*,tag) |
| 61 | | # annotated tag |
| 62 | | ;; |
| 63 | | refs/heads/*,commit) |
| 64 | | # branch |
| 65 | | ;; |
| 66 | | refs/remotes/*,commit) |
| 67 | | # tracking branch |
| 68 | | ;; |
| 69 | | *) |
| 70 | | # Anything else (is there anything else?) |
| 71 | | echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 |
| 72 | | exit 1 |
| 73 | | ;; |
| 74 | | esac |
| 75 | | |
| 76 | | # --- Finished |
| 77 | | exit 0 |
| toggle raw diff |
--- a/data/git-template/hooks/update
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/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, make this file executable by "chmod +x update".
-#
-# Config
-# ------
-# hooks.allowunannotated
-# This boolean sets whether unannotated tags will be allowed into the
-# repository. By default they won't be.
-#
-
-# --- 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-repo-config --bool hooks.allowunannotated)
-
-# check for no description
-projectdesc=$(sed -e '1p' "$GIT_DIR/description")
-if [ -z "$projectdesc" -o "$projectdesc" = "Unnamed repository; edit this file to name it for gitweb" ]; then
- echo "*** Project description file hasn't been set" >&2
- exit 1
-fi
-
-# --- Check types
-# if $newrev is 0000...0000, it's a commit to delete a branch
-if [ -z "${newrev##0*}" ]; then
- newrev_type=commit
-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/*,tag)
- # annotated tag
- ;;
- refs/heads/*,commit)
- # branch
- ;;
- refs/remotes/*,commit)
- # tracking branch
- ;;
- *)
- # 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 |
| |   |
| 1 | module Grit |
| 2 | class << self; attr_accessor :debug end |
| 3 | # self.debug = true |
| 4 | class Git |
| 5 | undef_method :clone |
| 6 | |
| 7 | class << self |
| 8 | attr_accessor :git_binary |
| 9 | end |
| 10 | |
| 11 | self.git_binary = "/usr/bin/env git" |
| 12 | |
| 13 | attr_accessor :git_dir |
| 14 | |
| 15 | def initialize(git_dir) |
| 16 | self.git_dir = git_dir |
| 17 | end |
| 18 | |
| 19 | def execute(command) |
| 20 | `#{command}` |
| 21 | end |
| 22 | |
| 23 | # Run the given git command with the specified arguments and return |
| 24 | # the result as a String |
| 25 | # +cmd+ is the command |
| 26 | # +options+ is a hash of Ruby style options |
| 27 | # +args+ is the list of arguments (to be joined by spaces) |
| 28 | # |
| 29 | # Examples |
| 30 | # git.rev_list({:max_count => 10, :header => true}, "master") |
| 31 | # |
| 32 | # Returns String |
| 33 | def method_missing(cmd, options = {}, *args) |
| 34 | opt_args = transform_options(options) |
| 35 | ext_args = args.map { |a| (a == '--' or a =~ /^\s*\|/) ? a : "'#{e(a)}'" } |
| 36 | |
| 37 | call = "#{Git.git_binary} --git-dir='#{self.git_dir}' #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}" |
| 38 | puts call if Grit.debug |
| 39 | response = execute(call) |
| 40 | puts response if Grit.debug |
| 41 | response |
| 42 | end |
| 43 | |
| 44 | def shell_escape(str) |
| 45 | str.to_s.gsub("'", "\\\\'") |
| 46 | end |
| 47 | alias_method :e, :shell_escape |
| 48 | |
| 49 | # Transform Ruby style options into git command line options |
| 50 | # +options+ is a hash of Ruby style options |
| 51 | # |
| 52 | |