summaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rwxr-xr-xcontrib/ciabot/ciabot.py2
-rwxr-xr-xcontrib/completion/git-completion.bash212
-rwxr-xr-xcontrib/examples/git-commit.sh2
-rwxr-xr-xcontrib/examples/git-fetch.sh4
-rwxr-xr-xcontrib/examples/git-merge.sh115
-rwxr-xr-xcontrib/examples/git-revert.sh1
-rwxr-xr-xcontrib/examples/git-svnimport.perl4
-rwxr-xr-xcontrib/fast-import/import-directories.perl3
-rwxr-xr-xcontrib/git-resurrect.sh1
-rw-r--r--contrib/git-shell-commands/README18
-rwxr-xr-xcontrib/git-shell-commands/help18
-rwxr-xr-xcontrib/git-shell-commands/list10
-rwxr-xr-xcontrib/hooks/post-receive-email88
-rw-r--r--contrib/svn-fe/.gitignore4
-rw-r--r--contrib/svn-fe/Makefile63
-rw-r--r--contrib/svn-fe/svn-fe.c16
-rw-r--r--contrib/svn-fe/svn-fe.txt67
-rwxr-xr-xcontrib/workdir/git-new-workdir6
18 files changed, 568 insertions, 66 deletions
diff --git a/contrib/ciabot/ciabot.py b/contrib/ciabot/ciabot.py
index d0627e0852..9775dffb5d 100755
--- a/contrib/ciabot/ciabot.py
+++ b/contrib/ciabot/ciabot.py
@@ -122,7 +122,7 @@ def report(refname, merged):
branch = os.path.basename(refname)
# Compute a shortnane for the revision
- rev = do("git describe ${merged} 2>/dev/null") or merged[:12]
+ rev = do("git describe '"+ merged +"' 2>/dev/null") or merged[:12]
# Extract the neta-information for the commit
rawcommit = do("git cat-file commit " + merged)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 545bd4b383..168669bbf7 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -21,6 +21,11 @@
# 2) Added the following line to your .bashrc:
# source ~/.git-completion.sh
#
+# Or, add the following lines to your .zshrc:
+# autoload bashcompinit
+# bashcompinit
+# source ~/.git-completion.sh
+#
# 3) Consider changing your PS1 to also show the current branch:
# PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
#
@@ -42,6 +47,24 @@
# set GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're
# untracked files, then a '%' will be shown next to the branch name.
#
+# If you would like to see the difference between HEAD and its
+# upstream, set GIT_PS1_SHOWUPSTREAM="auto". A "<" indicates
+# you are behind, ">" indicates you are ahead, and "<>"
+# indicates you have diverged. You can further control
+# behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated
+# list of values:
+# verbose show number of commits ahead/behind (+/-) upstream
+# legacy don't use the '--count' option available in recent
+# versions of git-rev-list
+# git always compare HEAD to @{upstream}
+# svn always compare HEAD to your SVN upstream
+# By default, __git_ps1 will compare HEAD to your SVN upstream
+# if it can find one, or @{upstream} otherwise. Once you have
+# set GIT_PS1_SHOWUPSTREAM, you can override it on a
+# per-repository basis by setting the bash.showUpstream config
+# variable.
+#
+#
# To submit patches:
#
# *) Read Documentation/SubmittingPatches
@@ -78,14 +101,134 @@ __gitdir ()
fi
}
+# stores the divergence from upstream in $p
+# used by GIT_PS1_SHOWUPSTREAM
+__git_ps1_show_upstream ()
+{
+ local key value
+ local svn_remote=() svn_url_pattern count n
+ local upstream=git legacy="" verbose=""
+
+ # get some config options from git-config
+ while read key value; do
+ case "$key" in
+ bash.showupstream)
+ GIT_PS1_SHOWUPSTREAM="$value"
+ if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then
+ p=""
+ return
+ fi
+ ;;
+ svn-remote.*.url)
+ svn_remote[ $((${#svn_remote[@]} + 1)) ]="$value"
+ svn_url_pattern+="\\|$value"
+ upstream=svn+git # default upstream is SVN if available, else git
+ ;;
+ esac
+ done < <(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')
+
+ # parse configuration values
+ for option in ${GIT_PS1_SHOWUPSTREAM}; do
+ case "$option" in
+ git|svn) upstream="$option" ;;
+ verbose) verbose=1 ;;
+ legacy) legacy=1 ;;
+ esac
+ done
+
+ # Find our upstream
+ case "$upstream" in
+ git) upstream="@{upstream}" ;;
+ svn*)
+ # get the upstream from the "git-svn-id: ..." in a commit message
+ # (git-svn uses essentially the same procedure internally)
+ local svn_upstream=($(git log --first-parent -1 \
+ --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null))
+ if [[ 0 -ne ${#svn_upstream[@]} ]]; then
+ svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]}
+ svn_upstream=${svn_upstream%@*}
+ local n_stop="${#svn_remote[@]}"
+ for ((n=1; n <= n_stop; ++n)); do
+ svn_upstream=${svn_upstream#${svn_remote[$n]}}
+ done
+
+ if [[ -z "$svn_upstream" ]]; then
+ # default branch name for checkouts with no layout:
+ upstream=${GIT_SVN_ID:-git-svn}
+ else
+ upstream=${svn_upstream#/}
+ fi
+ elif [[ "svn+git" = "$upstream" ]]; then
+ upstream="@{upstream}"
+ fi
+ ;;
+ esac
+
+ # Find how many commits we are ahead/behind our upstream
+ if [[ -z "$legacy" ]]; then
+ count="$(git rev-list --count --left-right \
+ "$upstream"...HEAD 2>/dev/null)"
+ else
+ # produce equivalent output to --count for older versions of git
+ local commits
+ if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)"
+ then
+ local commit behind=0 ahead=0
+ for commit in $commits
+ do
+ case "$commit" in
+ "<"*) let ++behind
+ ;;
+ *) let ++ahead
+ ;;
+ esac
+ done
+ count="$behind $ahead"
+ else
+ count=""
+ fi
+ fi
+
+ # calculate the result
+ if [[ -z "$verbose" ]]; then
+ case "$count" in
+ "") # no upstream
+ p="" ;;
+ "0 0") # equal to upstream
+ p="=" ;;
+ "0 "*) # ahead of upstream
+ p=">" ;;
+ *" 0") # behind upstream
+ p="<" ;;
+ *) # diverged from upstream
+ p="<>" ;;
+ esac
+ else
+ case "$count" in
+ "") # no upstream
+ p="" ;;
+ "0 0") # equal to upstream
+ p=" u=" ;;
+ "0 "*) # ahead of upstream
+ p=" u+${count#0 }" ;;
+ *" 0") # behind upstream
+ p=" u-${count% 0}" ;;
+ *) # diverged from upstream
+ p=" u+${count#* }-${count% *}" ;;
+ esac
+ fi
+
+}
+
+
# __git_ps1 accepts 0 or 1 arguments (i.e., format string)
# returns text to add to bash PS1 prompt (includes branch name)
__git_ps1 ()
{
local g="$(__gitdir)"
if [ -n "$g" ]; then
- local r
- local b
+ local r=""
+ local b=""
if [ -f "$g/rebase-merge/interactive" ]; then
r="|REBASE-i"
b="$(cat "$g/rebase-merge/head-name")"
@@ -127,11 +270,12 @@ __git_ps1 ()
}
fi
- local w
- local i
- local s
- local u
- local c
+ local w=""
+ local i=""
+ local s=""
+ local u=""
+ local c=""
+ local p=""
if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
@@ -159,10 +303,14 @@ __git_ps1 ()
u="%"
fi
fi
+
+ if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
+ __git_ps1_show_upstream
+ fi
fi
local f="$w$i$s$u"
- printf "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r"
+ printf "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p"
fi
}
@@ -797,6 +945,7 @@ _git_branch ()
__gitcomp "
--color --no-color --verbose --abbrev= --no-abbrev
--track --no-track --contains --merged --no-merged
+ --set-upstream
"
;;
*)
@@ -841,7 +990,7 @@ _git_checkout ()
--*)
__gitcomp "
--quiet --ours --theirs --track --no-track --merge
- --conflict= --patch
+ --conflict= --orphan --patch
"
;;
*)
@@ -982,7 +1131,7 @@ _git_diff ()
case "$cur" in
--*)
__gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
- --base --ours --theirs
+ --base --ours --theirs --no-index
$__git_diff_common_options
"
return
@@ -1051,7 +1200,7 @@ _git_format_patch ()
--numbered --start-number
--numbered-files
--keep-subject
- --signoff
+ --signoff --signature --no-signature
--in-reply-to= --cc=
--full-index --binary
--not --all
@@ -1725,6 +1874,7 @@ _git_config ()
format.headers
format.numbered
format.pretty
+ format.signature
format.signoff
format.subjectprefix
format.suffix
@@ -2195,6 +2345,11 @@ _git ()
{
local i c=1 command __git_dir
+ if [[ -n ${ZSH_VERSION-} ]]; then
+ emulate -L bash
+ setopt KSH_TYPESET
+ fi
+
while [ $c -lt $COMP_CWORD ]; do
i="${COMP_WORDS[c]}"
case "$i" in
@@ -2228,17 +2383,22 @@ _git ()
fi
local completion_func="_git_${command//-/_}"
- declare -F $completion_func >/dev/null && $completion_func && return
+ declare -f $completion_func >/dev/null && $completion_func && return
local expansion=$(__git_aliased_command "$command")
if [ -n "$expansion" ]; then
completion_func="_git_${expansion//-/_}"
- declare -F $completion_func >/dev/null && $completion_func
+ declare -f $completion_func >/dev/null && $completion_func
fi
}
_gitk ()
{
+ if [[ -n ${ZSH_VERSION-} ]]; then
+ emulate -L bash
+ setopt KSH_TYPESET
+ fi
+
__git_has_doubledash && return
local cur="${COMP_WORDS[COMP_CWORD]}"
@@ -2273,3 +2433,29 @@ if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
complete -o bashdefault -o default -o nospace -F _git git.exe 2>/dev/null \
|| complete -o default -o nospace -F _git git.exe
fi
+
+if [[ -n ${ZSH_VERSION-} ]]; then
+ shopt () {
+ local option
+ if [ $# -ne 2 ]; then
+ echo "USAGE: $0 (-q|-s|-u) <option>" >&2
+ return 1
+ fi
+ case "$2" in
+ nullglob)
+ option="$2"
+ ;;
+ *)
+ echo "$0: invalid option: $2" >&2
+ return 1
+ esac
+ case "$1" in
+ -q) setopt | grep -q "$option" ;;
+ -u) unsetopt "$option" ;;
+ -s) setopt "$option" ;;
+ *)
+ echo "$0: invalid flag: $1" >&2
+ return 1
+ esac
+ }
+fi
diff --git a/contrib/examples/git-commit.sh b/contrib/examples/git-commit.sh
index 5c72f655c7..23ffb028d1 100755
--- a/contrib/examples/git-commit.sh
+++ b/contrib/examples/git-commit.sh
@@ -631,7 +631,7 @@ then
if test -z "$quiet"
then
commit=`git diff-tree --always --shortstat --pretty="format:%h: %s"\
- --summary --root HEAD --`
+ --abbrev --summary --root HEAD --`
echo "Created${initial_commit:+ initial} commit $commit"
fi
fi
diff --git a/contrib/examples/git-fetch.sh b/contrib/examples/git-fetch.sh
index e44af2c86d..a314273bd5 100755
--- a/contrib/examples/git-fetch.sh
+++ b/contrib/examples/git-fetch.sh
@@ -127,10 +127,12 @@ then
orig_head=$(git rev-parse --verify HEAD 2>/dev/null)
fi
-# Allow --notags from remote.$1.tagopt
+# Allow --tags/--notags from remote.$1.tagopt
case "$tags$no_tags" in
'')
case "$(git config --get "remote.$1.tagopt")" in
+ --tags)
+ tags=t ;;
--no-tags)
no_tags=t ;;
esac
diff --git a/contrib/examples/git-merge.sh b/contrib/examples/git-merge.sh
index 8f617fcb70..7b922c3948 100755
--- a/contrib/examples/git-merge.sh
+++ b/contrib/examples/git-merge.sh
@@ -15,7 +15,10 @@ log add list of one-line log to merge commit message
squash create a single commit instead of doing a merge
commit perform a commit if the merge succeeds (default)
ff allow fast-forward (default)
+ff-only abort if fast-forward is not possible
+rerere-autoupdate update index with any reused conflict resolution
s,strategy= merge strategy to use
+X= option for selected merge strategy
m,message= message to be used for the merge commit (if any)
"
@@ -25,26 +28,32 @@ require_work_tree
cd_to_toplevel
test -z "$(git ls-files -u)" ||
- die "You are in the middle of a conflicted merge."
+ die "Merge is not possible because you have unmerged files."
+
+! test -e "$GIT_DIR/MERGE_HEAD" ||
+ die 'You have not concluded your merge (MERGE_HEAD exists).'
LF='
'
all_strategies='recur recursive octopus resolve stupid ours subtree'
all_strategies="$all_strategies recursive-ours recursive-theirs"
+not_strategies='base file index tree'
default_twohead_strategies='recursive'
default_octopus_strategies='octopus'
no_fast_forward_strategies='subtree ours'
no_trivial_strategies='recursive recur subtree ours recursive-ours recursive-theirs'
use_strategies=
+xopt=
allow_fast_forward=t
+fast_forward_only=
allow_trivial_merge=t
-squash= no_commit= log_arg=
+squash= no_commit= log_arg= rr_arg=
dropsave() {
rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" \
- "$GIT_DIR/MERGE_STASH" || exit 1
+ "$GIT_DIR/MERGE_STASH" "$GIT_DIR/MERGE_MODE" || exit 1
}
savestate() {
@@ -131,21 +140,34 @@ finish () {
merge_name () {
remote="$1"
rh=$(git rev-parse --verify "$remote^0" 2>/dev/null) || return
- bh=$(git show-ref -s --verify "refs/heads/$remote" 2>/dev/null)
- if test "$rh" = "$bh"
- then
- echo "$rh branch '$remote' of ."
- elif truname=$(expr "$remote" : '\(.*\)~[1-9][0-9]*$') &&
+ if truname=$(expr "$remote" : '\(.*\)~[0-9]*$') &&
git show-ref -q --verify "refs/heads/$truname" 2>/dev/null
then
echo "$rh branch '$truname' (early part) of ."
- elif test "$remote" = "FETCH_HEAD" -a -r "$GIT_DIR/FETCH_HEAD"
+ return
+ fi
+ if found_ref=$(git rev-parse --symbolic-full-name --verify \
+ "$remote" 2>/dev/null)
+ then
+ expanded=$(git check-ref-format --branch "$remote") ||
+ exit
+ if test "${found_ref#refs/heads/}" != "$found_ref"
+ then
+ echo "$rh branch '$expanded' of ."
+ return
+ elif test "${found_ref#refs/remotes/}" != "$found_ref"
+ then
+ echo "$rh remote branch '$expanded' of ."
+ return
+ fi
+ fi
+ if test "$remote" = "FETCH_HEAD" -a -r "$GIT_DIR/FETCH_HEAD"
then
sed -e 's/ not-for-merge / /' -e 1q \
"$GIT_DIR/FETCH_HEAD"
- else
- echo "$rh commit '$remote'"
+ return
fi
+ echo "$rh commit '$remote'"
}
parse_config () {
@@ -172,16 +194,36 @@ parse_config () {
--no-ff)
test "$squash" != t ||
die "You cannot combine --squash with --no-ff."
+ test "$fast_forward_only" != t ||
+ die "You cannot combine --ff-only with --no-ff."
allow_fast_forward=f ;;
+ --ff-only)
+ test "$allow_fast_forward" != f ||
+ die "You cannot combine --ff-only with --no-ff."
+ fast_forward_only=t ;;
+ --rerere-autoupdate|--no-rerere-autoupdate)
+ rr_arg=$1 ;;
-s|--strategy)
shift
case " $all_strategies " in
*" $1 "*)
- use_strategies="$use_strategies$1 " ;;
+ use_strategies="$use_strategies$1 "
+ ;;
*)
- die "available strategies are: $all_strategies" ;;
+ case " $not_strategies " in
+ *" $1 "*)
+ false
+ esac &&
+ type "git-merge-$1" >/dev/null 2>&1 ||
+ die "available strategies are: $all_strategies"
+ use_strategies="$use_strategies$1 "
+ ;;
esac
;;
+ -X)
+ shift
+ xopt="${xopt:+$xopt }$(git rev-parse --sq-quote "--$1")"
+ ;;
-m|--message)
shift
merge_msg="$1"
@@ -245,6 +287,10 @@ then
exit 1
fi
+ test "$squash" != t ||
+ die "Squash commit into empty head not supported yet"
+ test "$allow_fast_forward" = t ||
+ die "Non-fast-forward into an empty head does not make sense"
rh=$(git rev-parse --verify "$1^0") ||
die "$1 - not something we can merge"
@@ -261,12 +307,18 @@ else
# the given message. If remote is invalid we will die
# later in the common codepath so we discard the error
# in this loop.
- merge_name=$(for remote
+ merge_msg="$(
+ for remote
do
merge_name "$remote"
- done | git fmt-merge-msg $log_arg
- )
- merge_msg="${merge_msg:+$merge_msg$LF$LF}$merge_name"
+ done |
+ if test "$have_message" = t
+ then
+ git fmt-merge-msg -m "$merge_msg" $log_arg
+ else
+ git fmt-merge-msg $log_arg
+ fi
+ )"
fi
head=$(git rev-parse --verify "$head_arg"^0) || usage
@@ -335,7 +387,7 @@ case "$#" in
common=$(git merge-base --all $head "$@")
;;
*)
- common=$(git show-branch --merge-base $head "$@")
+ common=$(git merge-base --all --octopus $head "$@")
;;
esac
echo "$head" >"$GIT_DIR/ORIG_HEAD"
@@ -373,8 +425,8 @@ t,1,"$head",*)
# We are not doing octopus, not fast-forward, and have only
# one common.
git update-index --refresh 2>/dev/null
- case "$allow_trivial_merge" in
- t)
+ case "$allow_trivial_merge,$fast_forward_only" in
+ t,)
# See if it is really trivial.
git var GIT_COMMITTER_IDENT >/dev/null || exit
echo "Trying really trivial in-index merge..."
@@ -413,6 +465,11 @@ t,1,"$head",*)
;;
esac
+if test "$fast_forward_only" = t
+then
+ die "Not possible to fast-forward, aborting."
+fi
+
# We are going to make a new commit.
git var GIT_COMMITTER_IDENT >/dev/null || exit
@@ -451,7 +508,7 @@ do
# Remember which strategy left the state in the working tree
wt_strategy=$strategy
- git-merge-$strategy $common -- "$head_arg" "$@"
+ eval 'git-merge-$strategy '"$xopt"' $common -- "$head_arg" "$@"'
exit=$?
if test "$no_commit" = t && test "$exit" = 0
then
@@ -489,9 +546,9 @@ if test '' != "$result_tree"
then
if test "$allow_fast_forward" = "t"
then
- parents=$(git show-branch --independent "$head" "$@")
+ parents=$(git merge-base --independent "$head" "$@")
else
- parents=$(git rev-parse "$head" "$@")
+ parents=$(git rev-parse "$head" "$@")
fi
parents=$(echo "$parents" | sed -e 's/^/-p /')
result_commit=$(printf '%s\n' "$merge_msg" | git commit-tree $result_tree $parents) || exit
@@ -533,7 +590,15 @@ else
do
echo $remote
done >"$GIT_DIR/MERGE_HEAD"
- printf '%s\n' "$merge_msg" >"$GIT_DIR/MERGE_MSG"
+ printf '%s\n' "$merge_msg" >"$GIT_DIR/MERGE_MSG" ||
+ die "Could not write to $GIT_DIR/MERGE_MSG"
+ if test "$allow_fast_forward" != t
+ then
+ printf "%s" no-ff
+ else
+ :
+ fi >"$GIT_DIR/MERGE_MODE" ||
+ die "Could not write to $GIT_DIR/MERGE_MODE"
fi
if test "$merge_was_ok" = t
@@ -550,6 +615,6 @@ Conflicts:
sed -e 's/^[^ ]* / /' |
uniq
} >>"$GIT_DIR/MERGE_MSG"
- git rerere
+ git rerere $rr_arg
die "Automatic merge failed; fix conflicts and then commit the result."
fi
diff --git a/contrib/examples/git-revert.sh b/contrib/examples/git-revert.sh
index 49f00321b2..60a05a8b97 100755
--- a/contrib/examples/git-revert.sh
+++ b/contrib/examples/git-revert.sh
@@ -181,7 +181,6 @@ Conflicts:
esac
exit 1
}
-echo >&2 "Finished one $me."
# If we are cherry-pick, and if the merge did not result in
# hand-editing, we will hit this commit and inherit the original
diff --git a/contrib/examples/git-svnimport.perl b/contrib/examples/git-svnimport.perl
index 4576c4a862..b09ff8f12f 100755
--- a/contrib/examples/git-svnimport.perl
+++ b/contrib/examples/git-svnimport.perl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
# This tool is copyright (c) 2005, Matthias Urlichs.
# It is released under the Gnu Public License, version 2.
@@ -289,7 +289,7 @@ my $current_rev = $opt_s || 1;
unless(-d $git_dir) {
system("git init");
die "Cannot init the GIT db at $git_tree: $?\n" if $?;
- system("git read-tree");
+ system("git read-tree --empty");
die "Cannot init an empty tree: $?\n" if $?;
$last_branch = $opt_o;
diff --git a/contrib/fast-import/import-directories.perl b/contrib/fast-import/import-directories.perl
index 3a5da4ab00..7f3afa5ac4 100755
--- a/contrib/fast-import/import-directories.perl
+++ b/contrib/fast-import/import-directories.perl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
#
# Copyright 2008-2009 Peter Krefting <peter@softwolves.pp.se>
#
@@ -140,6 +140,7 @@ by whitespace or other characters.
# Globals
use strict;
+use warnings;
use integer;
my $crlfmode = 0;
my @revs;
diff --git a/contrib/git-resurrect.sh b/contrib/git-resurrect.sh
index c364dda696..a4ed4c3c62 100755
--- a/contrib/git-resurrect.sh
+++ b/contrib/git-resurrect.sh
@@ -9,6 +9,7 @@ other/Merge <other> into <name> (respectively) commit subjects, which
is rather slow but allows you to resurrect other people's topic
branches."
+OPTIONS_KEEPDASHDASH=
OPTIONS_SPEC="\
git resurrect $USAGE
--
diff --git a/contrib/git-shell-commands/README b/contrib/git-shell-commands/README
new file mode 100644
index 0000000000..438463b160
--- /dev/null
+++ b/contrib/git-shell-commands/README
@@ -0,0 +1,18 @@
+Sample programs callable through git-shell. Place a directory named
+'git-shell-commands' in the home directory of a user whose shell is
+git-shell. Then anyone logging in as that user will be able to run
+executables in the 'git-shell-commands' directory.
+
+Provided commands:
+
+help: Prints out the names of available commands. When run
+interactively, git-shell will automatically run 'help' on startup,
+provided it exists.
+
+list: Displays any bare repository whose name ends with ".git" under
+user's home directory. No other git repositories are visible,
+although they might be clonable through git-shell. 'list' is designed
+to minimize the number of calls to git that must be made in finding
+available repositories; if your setup has additional repositories that
+should be user-discoverable, you may wish to modify 'list'
+accordingly.
diff --git a/contrib/git-shell-commands/help b/contrib/git-shell-commands/help
new file mode 100755
index 0000000000..535770c6ec
--- /dev/null
+++ b/contrib/git-shell-commands/help
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+if tty -s
+then
+ echo "Run 'help' for help, or 'exit' to leave. Available commands:"
+else
+ echo "Run 'help' for help. Available commands:"
+fi
+
+cd "$(dirname "$0")"
+
+for cmd in *
+do
+ case "$cmd" in
+ help) ;;
+ *) [ -f "$cmd" ] && [ -x "$cmd" ] && echo "$cmd" ;;
+ esac
+done
diff --git a/contrib/git-shell-commands/list b/contrib/git-shell-commands/list
new file mode 100755
index 0000000000..6f89938821
--- /dev/null
+++ b/contrib/git-shell-commands/list
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+print_if_bare_repo='
+ if "$(git --git-dir="$1" rev-parse --is-bare-repository)" = true
+ then
+ printf "%s\n" "${1#./}"
+ fi
+'
+
+find -type d -name "*.git" -exec sh -c "$print_if_bare_repo" -- \{} \; -prune 2>/dev/null
diff --git a/contrib/hooks/post-receive-email b/contrib/hooks/post-receive-email
index 58a35c8287..85724bfc08 100755
--- a/contrib/hooks/post-receive-email
+++ b/contrib/hooks/post-receive-email
@@ -23,6 +23,13 @@
# possible for the email to be from someone other than the person doing the
# push.
#
+# To help with debugging and use on pre-v1.5.1 git servers, this script will
+# also obey the interface of hooks/update, taking its arguments on the
+# command line. Unfortunately, hooks/update is called once for each ref.
+# To avoid firing one email per ref, this script just prints its output to
+# the screen when used in this mode. The output can then be redirected if
+# wanted.
+#
# Config
# ------
# hooks.mailinglist
@@ -48,6 +55,11 @@
# "t=%s; printf 'http://.../?id=%%s' \$t; echo;echo; git show -C \$t; echo"
# Be careful if "..." contains things that will be expanded by shell "eval"
# or printf.
+# hooks.emailmaxlines
+# The maximum number of lines that should be included in the generated
+# email body. If not specified, there is no limit.
+# Lines beyond the limit are suppressed and counted, and a final
+# line is added indicating the number of suppressed lines.
#
# Notes
# -----
@@ -59,24 +71,16 @@
# ---------------------------- Functions
#
-# Top level email generation function. This decides what type of update
-# this is and calls the appropriate body-generation routine after outputting
-# the common header
-#
-# Note this function doesn't actually generate any email output, that is
-# taken care of by the functions it calls:
-# - generate_email_header
-# - generate_create_XXXX_email
-# - generate_update_XXXX_email
-# - generate_delete_XXXX_email
-# - generate_email_footer
+# Function to prepare for email generation. This decides what type
+# of update this is and whether an email should even be generated.
#
-generate_email()
+prep_for_email()
{
# --- Arguments
oldrev=$(git rev-parse $1)
newrev=$(git rev-parse $2)
refname="$3"
+ maxlines=$4
# --- Interpret
# 0000->1234 (create)
@@ -146,7 +150,7 @@ generate_email()
# Anything else (is there anything else?)
echo >&2 "*** Unknown type of update to $refname ($rev_type)"
echo >&2 "*** - no email generated"
- exit 1
+ return 0
;;
esac
@@ -162,9 +166,32 @@ generate_email()
esac
echo >&2 "*** $config_name is not set so no email will be sent"
echo >&2 "*** for $refname update $oldrev->$newrev"
- exit 0
+ return 0
fi
+ return 1
+}
+
+#
+# Top level email generation function. This calls the appropriate
+# body-generation routine after outputting the common header.
+#
+# Note this function doesn't actually generate any email output, that is
+# taken care of by the functions it calls:
+# - generate_email_header
+# - generate_create_XXXX_email
+# - generate_update_XXXX_email
+# - generate_delete_XXXX_email
+# - generate_email_footer
+#
+# Note also that this function cannot 'exit' from the script; when this
+# function is running (in hook script mode), the send_mail() function
+# is already executing in another process, connected via a pipe, and
+# if this function exits without, whatever has been generated to that
+# point will be sent as an email... even if nothing has been generated.
+#
+generate_email()
+{
# Email parameters
# The email subject will contain the best description of the ref
# that we can build from the parameters
@@ -185,7 +212,12 @@ generate_email()
fn_name=atag
;;
esac
- generate_${change_type}_${fn_name}_email
+
+ if [ -z "$maxlines" ]; then
+ generate_${change_type}_${fn_name}_email
+ else
+ generate_${change_type}_${fn_name}_email | limit_lines $maxlines
+ fi
generate_email_footer
}
@@ -196,7 +228,7 @@ generate_email_header()
# Generate header
cat <<-EOF
To: $recipients
- Subject: ${emailprefix}$projectdesc $refname_type, $short_refname, ${change_type}d. $describe
+ Subject: ${emailprefix}$projectdesc $refname_type $short_refname ${change_type}d. $describe
X-Git-Refname: $refname
X-Git-Reftype: $refname_type
X-Git-Oldrev: $oldrev
@@ -635,6 +667,24 @@ show_new_revisions()
}
+limit_lines()
+{
+ lines=0
+ skipped=0
+ while IFS="" read -r line; do
+ lines=$((lines + 1))
+ if [ $lines -gt $1 ]; then
+ skipped=$((skipped + 1))
+ else
+ printf "%s\n" "$line"
+ fi
+ done
+ if [ $skipped -ne 0 ]; then
+ echo "... $skipped lines suppressed ..."
+ fi
+}
+
+
send_mail()
{
if [ -n "$envelopesender" ]; then
@@ -672,6 +722,7 @@ announcerecipients=$(git config hooks.announcelist)
envelopesender=$(git config hooks.envelopesender)
emailprefix=$(git config hooks.emailprefix || echo '[SCM] ')
custom_showrev=$(git config hooks.showrev)
+maxlines=$(git config hooks.emailmaxlines)
# --- Main loop
# Allow dual mode: run from the command line just like the update hook, or
@@ -680,10 +731,11 @@ if [ -n "$1" -a -n "$2" -a -n "$3" ]; then
# Output to the terminal in command line mode - if someone wanted to
# resend an email; they could redirect the output to sendmail
# themselves
- PAGER= generate_email $2 $3 $1
+ prep_for_email $2 $3 $1 && PAGER= generate_email
else
while read oldrev newrev refname
do
- generate_email $oldrev $newrev $refname | send_mail
+ prep_for_email $oldrev $newrev $refname || continue
+ generate_email $maxlines | send_mail
done
fi
diff --git a/contrib/svn-fe/.gitignore b/contrib/svn-fe/.gitignore
new file mode 100644
index 0000000000..02a7791585
--- /dev/null
+++ b/contrib/svn-fe/.gitignore
@@ -0,0 +1,4 @@
+/*.xml
+/*.1
+/*.html
+/svn-fe
diff --git a/contrib/svn-fe/Makefile b/contrib/svn-fe/Makefile
new file mode 100644
index 0000000000..360d8da417
--- /dev/null
+++ b/contrib/svn-fe/Makefile
@@ -0,0 +1,63 @@
+all:: svn-fe$X
+
+CC = gcc
+RM = rm -f
+MV = mv
+
+CFLAGS = -g -O2 -Wall
+LDFLAGS =
+ALL_CFLAGS = $(CFLAGS)
+ALL_LDFLAGS = $(LDFLAGS)
+EXTLIBS =
+
+GIT_LIB = ../../libgit.a
+VCSSVN_LIB = ../../vcs-svn/lib.a
+LIBS = $(VCSSVN_LIB) $(GIT_LIB) $(EXTLIBS)
+
+QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
+QUIET_SUBDIR1 =
+
+ifneq ($(findstring $(MAKEFLAGS),w),w)
+PRINT_DIR = --no-print-directory
+else # "make -w"
+NO_SUBDIR = :
+endif
+
+ifneq ($(findstring $(MAKEFLAGS),s),s)
+ifndef V
+ QUIET_CC = @echo ' ' CC $@;
+ QUIET_LINK = @echo ' ' LINK $@;
+ QUIET_SUBDIR0 = +@subdir=
+ QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
+ $(MAKE) $(PRINT_DIR) -C $$subdir
+endif
+endif
+
+svn-fe$X: svn-fe.o $(VCSSVN_LIB) $(GIT_LIB)
+ $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ svn-fe.o \
+ $(ALL_LDFLAGS) $(LIBS)
+
+svn-fe.o: svn-fe.c ../../vcs-svn/svndump.h
+ $(QUIET_CC)$(CC) -I../../vcs-svn -o $*.o -c $(ALL_CFLAGS) $<
+
+svn-fe.html: svn-fe.txt
+ $(QUIET_SUBDIR0)../../Documentation $(QUIET_SUBDIR1) \
+ MAN_TXT=../contrib/svn-fe/svn-fe.txt \
+ ../contrib/svn-fe/$@
+
+svn-fe.1: svn-fe.txt
+ $(QUIET_SUBDIR0)../../Documentation $(QUIET_SUBDIR1) \
+ MAN_TXT=../contrib/svn-fe/svn-fe.txt \
+ ../contrib/svn-fe/$@
+ $(MV) ../../Documentation/svn-fe.1 .
+
+../../vcs-svn/lib.a: FORCE
+ $(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) vcs-svn/lib.a
+
+../../libgit.a: FORCE
+ $(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) libgit.a
+
+clean:
+ $(RM) svn-fe$X svn-fe.o svn-fe.html svn-fe.xml svn-fe.1
+
+.PHONY: all clean FORCE
diff --git a/contrib/svn-fe/svn-fe.c b/contrib/svn-fe/svn-fe.c
new file mode 100644
index 0000000000..a2677b03e0
--- /dev/null
+++ b/contrib/svn-fe/svn-fe.c
@@ -0,0 +1,16 @@
+/*
+ * This file is in the public domain.
+ * You may freely use, modify, distribute, and relicense it.
+ */
+
+#include <stdlib.h>
+#include "svndump.h"
+
+int main(int argc, char **argv)
+{
+ svndump_init(NULL);
+ svndump_read((argc > 1) ? argv[1] : NULL);
+ svndump_deinit();
+ svndump_reset();
+ return 0;
+}
diff --git a/contrib/svn-fe/svn-fe.txt b/contrib/svn-fe/svn-fe.txt
new file mode 100644
index 0000000000..35f84bd9e7
--- /dev/null
+++ b/contrib/svn-fe/svn-fe.txt
@@ -0,0 +1,67 @@
+svn-fe(1)
+=========
+
+NAME
+----
+svn-fe - convert an SVN "dumpfile" to a fast-import stream
+
+SYNOPSIS
+--------
+svnadmin dump --incremental REPO | svn-fe [url] | git fast-import
+
+DESCRIPTION
+-----------
+
+Converts a Subversion dumpfile into input suitable for
+git-fast-import(1) and similar importers. REPO is a path to a
+Subversion repository mirrored on the local disk. Remote Subversion
+repositories can be mirrored on local disk using the `svnsync`
+command.
+
+INPUT FORMAT
+------------
+Subversion's repository dump format is documented in full in
+`notes/dump-load-format.txt` from the Subversion source tree.
+Files in this format can be generated using the 'svnadmin dump' or
+'svk admin dump' command.
+
+Dumps produced with 'svnadmin dump --deltas' (dumpfile format v3)
+are not supported.
+
+OUTPUT FORMAT
+-------------
+The fast-import format is documented by the git-fast-import(1)
+manual page.
+
+NOTES
+-----
+Subversion dumps do not record a separate author and committer for
+each revision, nor a separate display name and email address for
+each author. Like git-svn(1), 'svn-fe' will use the name
+
+---------
+user <user@UUID>
+---------
+
+as committer, where 'user' is the value of the `svn:author` property
+and 'UUID' the repository's identifier.
+
+To support incremental imports, 'svn-fe' puts a `git-svn-id` line at
+the end of each commit log message if passed an url on the command
+line. This line has the form `git-svn-id: URL@REVNO UUID`.
+
+The resulting repository will generally require further processing
+to put each project in its own repository and to separate the history
+of each branch. The 'git filter-branch --subdirectory-filter' command
+may be useful for this purpose.
+
+BUGS
+----
+Empty directories and unknown properties are silently discarded.
+
+The exit status does not reflect whether an error was detected.
+
+SEE ALSO
+--------
+git-svn(1), svn2git(1), svk(1), git-filter-branch(1), git-fast-import(1),
+https://svn.apache.org/repos/asf/subversion/trunk/notes/dump-load-format.txt
diff --git a/contrib/workdir/git-new-workdir b/contrib/workdir/git-new-workdir
index 993cacf324..75e8b25817 100755
--- a/contrib/workdir/git-new-workdir
+++ b/contrib/workdir/git-new-workdir
@@ -42,7 +42,7 @@ then
fi
# don't link to a workdir
-if test -L "$git_dir/config"
+if test -h "$git_dir/config"
then
die "\"$orig_git\" is a working directory only, please specify" \
"a complete repository."
@@ -54,13 +54,13 @@ then
die "destination directory '$new_workdir' already exists."
fi
-# make sure the the links use full paths
+# make sure the links use full paths
git_dir=$(cd "$git_dir"; pwd)
# create the workdir
mkdir -p "$new_workdir/.git" || die "unable to create \"$new_workdir\"!"
-# create the links to the original repo. explictly exclude index, HEAD and
+# create the links to the original repo. explicitly exclude index, HEAD and
# logs/HEAD from the list since they are purely related to the current working
# directory, and should not be shared.
for x in config refs logs/refs objects info hooks packed-refs remotes rr-cache svn