Initial class construction

This commit is contained in:
João Narciso
2019-05-06 16:34:28 +02:00
parent 67f2d57e03
commit 431ff5f7d4
5813 changed files with 1622108 additions and 0 deletions

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,348 @@
#!/bin/sh
USAGE='[help|start|bad|good|new|old|terms|skip|next|reset|visualize|view|replay|log|run]'
LONG_USAGE='git bisect help
print this long help message.
git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
[--no-checkout] [<bad> [<good>...]] [--] [<pathspec>...]
reset bisect state and start bisection.
git bisect (bad|new) [<rev>]
mark <rev> a known-bad revision/
a revision after change in a given property.
git bisect (good|old) [<rev>...]
mark <rev>... known-good revisions/
revisions before change in a given property.
git bisect terms [--term-good | --term-bad]
show the terms used for old and new commits (default: bad, good)
git bisect skip [(<rev>|<range>)...]
mark <rev>... untestable revisions.
git bisect next
find next bisection to test and check it out.
git bisect reset [<commit>]
finish bisection search and go back to commit.
git bisect (visualize|view)
show bisect status in gitk.
git bisect replay <logfile>
replay bisection log.
git bisect log
show bisect log.
git bisect run <cmd>...
use <cmd>... to automatically bisect.
Please use "git help bisect" to get the full man page.'
OPTIONS_SPEC=
. git-sh-setup
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
TERM_BAD=bad
TERM_GOOD=good
bisect_head()
{
if test -f "$GIT_DIR/BISECT_HEAD"
then
echo BISECT_HEAD
else
echo HEAD
fi
}
bisect_autostart() {
test -s "$GIT_DIR/BISECT_START" || {
gettextln "You need to start by \"git bisect start\"" >&2
if test -t 0
then
# TRANSLATORS: Make sure to include [Y] and [n] in your
# translation. The program will only accept English input
# at this point.
gettext "Do you want me to do it for you [Y/n]? " >&2
read yesno
case "$yesno" in
[Nn]*)
exit ;;
esac
bisect_start
else
exit 1
fi
}
}
bisect_start() {
git bisect--helper --bisect-start $@ || exit
#
# Change state.
# In case of mistaken revs or checkout error, or signals received,
# "bisect_auto_next" below may exit or misbehave.
# We have to trap this to be able to clean up using
# "bisect_clean_state".
#
trap 'git bisect--helper --bisect-clean-state' 0
trap 'exit 255' 1 2 3 15
#
# Check if we can proceed to the next bisect state.
#
get_terms
bisect_auto_next
trap '-' 0
}
bisect_skip() {
all=''
for arg in "$@"
do
case "$arg" in
*..*)
revs=$(git rev-list "$arg") || die "$(eval_gettext "Bad rev input: \$arg")" ;;
*)
revs=$(git rev-parse --sq-quote "$arg") ;;
esac
all="$all $revs"
done
eval bisect_state 'skip' $all
}
bisect_state() {
bisect_autostart
state=$1
git bisect--helper --check-and-set-terms $state $TERM_GOOD $TERM_BAD || exit
get_terms
case "$#,$state" in
0,*)
die "Please call 'bisect_state' with at least one argument." ;;
1,"$TERM_BAD"|1,"$TERM_GOOD"|1,skip)
bisected_head=$(bisect_head)
rev=$(git rev-parse --verify "$bisected_head") ||
die "$(eval_gettext "Bad rev input: \$bisected_head")"
git bisect--helper --bisect-write "$state" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit
git bisect--helper --check-expected-revs "$rev" ;;
2,"$TERM_BAD"|*,"$TERM_GOOD"|*,skip)
shift
hash_list=''
for rev in "$@"
do
sha=$(git rev-parse --verify "$rev^{commit}") ||
die "$(eval_gettext "Bad rev input: \$rev")"
hash_list="$hash_list $sha"
done
for rev in $hash_list
do
git bisect--helper --bisect-write "$state" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit
done
git bisect--helper --check-expected-revs $hash_list ;;
*,"$TERM_BAD")
die "$(eval_gettext "'git bisect \$TERM_BAD' can take only one argument.")" ;;
*)
usage ;;
esac
bisect_auto_next
}
bisect_auto_next() {
git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD && bisect_next || :
}
bisect_next() {
case "$#" in 0) ;; *) usage ;; esac
bisect_autostart
git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD $TERM_GOOD|| exit
# Perform all bisection computation, display and checkout
git bisect--helper --next-all $(test -f "$GIT_DIR/BISECT_HEAD" && echo --no-checkout)
res=$?
# Check if we should exit because bisection is finished
if test $res -eq 10
then
bad_rev=$(git show-ref --hash --verify refs/bisect/$TERM_BAD)
bad_commit=$(git show-branch $bad_rev)
echo "# first $TERM_BAD commit: $bad_commit" >>"$GIT_DIR/BISECT_LOG"
exit 0
elif test $res -eq 2
then
echo "# only skipped commits left to test" >>"$GIT_DIR/BISECT_LOG"
good_revs=$(git for-each-ref --format="%(objectname)" "refs/bisect/$TERM_GOOD-*")
for skipped in $(git rev-list refs/bisect/$TERM_BAD --not $good_revs)
do
skipped_commit=$(git show-branch $skipped)
echo "# possible first $TERM_BAD commit: $skipped_commit" >>"$GIT_DIR/BISECT_LOG"
done
exit $res
fi
# Check for an error in the bisection process
test $res -ne 0 && exit $res
return 0
}
bisect_visualize() {
git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit
if test $# = 0
then
if test -n "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" &&
type gitk >/dev/null 2>&1
then
set gitk
else
set git log
fi
else
case "$1" in
git*|tig) ;;
-*) set git log "$@" ;;
*) set git "$@" ;;
esac
fi
eval '"$@"' --bisect -- $(cat "$GIT_DIR/BISECT_NAMES")
}
bisect_replay () {
file="$1"
test "$#" -eq 1 || die "$(gettext "No logfile given")"
test -r "$file" || die "$(eval_gettext "cannot read \$file for replaying")"
git bisect--helper --bisect-reset || exit
while read git bisect command rev
do
test "$git $bisect" = "git bisect" || test "$git" = "git-bisect" || continue
if test "$git" = "git-bisect"
then
rev="$command"
command="$bisect"
fi
get_terms
git bisect--helper --check-and-set-terms "$command" "$TERM_GOOD" "$TERM_BAD" || exit
get_terms
case "$command" in
start)
cmd="bisect_start $rev"
eval "$cmd" ;;
"$TERM_GOOD"|"$TERM_BAD"|skip)
git bisect--helper --bisect-write "$command" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit;;
terms)
git bisect--helper --bisect-terms $rev || exit;;
*)
die "$(gettext "?? what are you talking about?")" ;;
esac
done <"$file"
bisect_auto_next
}
bisect_run () {
git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit
test -n "$*" || die "$(gettext "bisect run failed: no command provided.")"
while true
do
command="$@"
eval_gettextln "running \$command"
"$@"
res=$?
# Check for really bad run error.
if [ $res -lt 0 -o $res -ge 128 ]
then
eval_gettextln "bisect run failed:
exit code \$res from '\$command' is < 0 or >= 128" >&2
exit $res
fi
# Find current state depending on run success or failure.
# A special exit code of 125 means cannot test.
if [ $res -eq 125 ]
then
state='skip'
elif [ $res -gt 0 ]
then
state="$TERM_BAD"
else
state="$TERM_GOOD"
fi
# We have to use a subshell because "bisect_state" can exit.
( bisect_state $state >"$GIT_DIR/BISECT_RUN" )
res=$?
cat "$GIT_DIR/BISECT_RUN"
if sane_grep "first $TERM_BAD commit could be any of" "$GIT_DIR/BISECT_RUN" \
>/dev/null
then
gettextln "bisect run cannot continue any more" >&2
exit $res
fi
if [ $res -ne 0 ]
then
eval_gettextln "bisect run failed:
'bisect_state \$state' exited with error code \$res" >&2
exit $res
fi
if sane_grep "is the first $TERM_BAD commit" "$GIT_DIR/BISECT_RUN" >/dev/null
then
gettextln "bisect run success"
exit 0;
fi
done
}
bisect_log () {
test -s "$GIT_DIR/BISECT_LOG" || die "$(gettext "We are not bisecting.")"
cat "$GIT_DIR/BISECT_LOG"
}
get_terms () {
if test -s "$GIT_DIR/BISECT_TERMS"
then
{
read TERM_BAD
read TERM_GOOD
} <"$GIT_DIR/BISECT_TERMS"
fi
}
case "$#" in
0)
usage ;;
*)
cmd="$1"
get_terms
shift
case "$cmd" in
help)
git bisect -h ;;
start)
bisect_start "$@" ;;
bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
bisect_state "$cmd" "$@" ;;
skip)
bisect_skip "$@" ;;
next)
# Not sure we want "next" at the UI level anymore.
bisect_next "$@" ;;
visualize|view)
bisect_visualize "$@" ;;
reset)
git bisect--helper --bisect-reset "$@" ;;
replay)
bisect_replay "$@" ;;
log)
bisect_log ;;
run)
bisect_run "$@" ;;
terms)
git bisect--helper --bisect-terms "$@" || exit;;
*)
usage ;;
esac
esac

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,25 @@
#!/bin/sh
# Tcl ignores the next line -*- tcl -*- \
exec wish "$0" -- "$@"
if { $argc >=2 && [lindex $argv 0] == "--working-dir" } {
set workdir [lindex $argv 1]
cd $workdir
if {[lindex [file split $workdir] end] eq {.git}} {
# Workaround for Explorer right click "Git GUI Here" on .git/
cd ..
}
set argv [lrange $argv 2 end]
incr argc -2
}
set basedir [file dirname \
[file dirname \
[file dirname [info script]]]]
set bindir [file join $basedir bin]
set bindir "$bindir;[file join $basedir mingw bin]"
regsub -all ";" $bindir "\\;" bindir
set env(PATH) "$bindir;$env(PATH)"
unset bindir
source [file join [file dirname [info script]] git-gui.tcl]

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,105 @@
#!/bin/sh
# git-difftool--helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher.
# This script is typically launched by using the 'git difftool'
# convenience command.
#
# Copyright (c) 2009, 2010 David Aguilar
TOOL_MODE=diff
. git-mergetool--lib
# difftool.prompt controls the default prompt/no-prompt behavior
# and is overridden with $GIT_DIFFTOOL*_PROMPT.
should_prompt () {
prompt_merge=$(git config --bool mergetool.prompt || echo true)
prompt=$(git config --bool difftool.prompt || echo $prompt_merge)
if test "$prompt" = true
then
test -z "$GIT_DIFFTOOL_NO_PROMPT"
else
test -n "$GIT_DIFFTOOL_PROMPT"
fi
}
# Indicates that --extcmd=... was specified
use_ext_cmd () {
test -n "$GIT_DIFFTOOL_EXTCMD"
}
launch_merge_tool () {
# Merged is the filename as it appears in the work tree
# Local is the contents of a/filename
# Remote is the contents of b/filename
# Custom merge tool commands might use $BASE so we provide it
MERGED="$1"
LOCAL="$2"
REMOTE="$3"
BASE="$1"
# $LOCAL and $REMOTE are temporary files so prompt
# the user with the real $MERGED name before launching $merge_tool.
if should_prompt
then
printf "\nViewing (%s/%s): '%s'\n" "$GIT_DIFF_PATH_COUNTER" \
"$GIT_DIFF_PATH_TOTAL" "$MERGED"
if use_ext_cmd
then
printf "Launch '%s' [Y/n]? " \
"$GIT_DIFFTOOL_EXTCMD"
else
printf "Launch '%s' [Y/n]? " "$merge_tool"
fi
read ans || return
if test "$ans" = n
then
return
fi
fi
if use_ext_cmd
then
export BASE
eval $GIT_DIFFTOOL_EXTCMD '"$LOCAL"' '"$REMOTE"'
else
run_merge_tool "$merge_tool"
fi
}
if ! use_ext_cmd
then
if test -n "$GIT_DIFF_TOOL"
then
merge_tool="$GIT_DIFF_TOOL"
else
merge_tool="$(get_merge_tool)" || exit
fi
fi
if test -n "$GIT_DIFFTOOL_DIRDIFF"
then
LOCAL="$1"
REMOTE="$2"
run_merge_tool "$merge_tool" false
else
# Launch the merge tool on each path provided by 'git diff'
while test $# -gt 6
do
launch_merge_tool "$1" "$2" "$5"
status=$?
if test $status -ge 126
then
# Command not found (127), not executable (126) or
# exited via a signal (>= 128).
exit $status
fi
if test "$status" != 0 &&
test "$GIT_DIFFTOOL_TRUST_EXIT_CODE" = true
then
exit $status
fi
shift 7
done
fi
exit 0

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,662 @@
#!/bin/sh
#
# Rewrite revision history
# Copyright (c) Petr Baudis, 2006
# Minimal changes to "port" it to core-git (c) Johannes Schindelin, 2007
#
# Lets you rewrite the revision history of the current branch, creating
# a new branch. You can specify a number of filters to modify the commits,
# files and trees.
# The following functions will also be available in the commit filter:
functions=$(cat << \EOF
EMPTY_TREE=$(git hash-object -t tree /dev/null)
warn () {
echo "$*" >&2
}
map()
{
# if it was not rewritten, take the original
if test -r "$workdir/../map/$1"
then
cat "$workdir/../map/$1"
else
echo "$1"
fi
}
# if you run 'skip_commit "$@"' in a commit filter, it will print
# the (mapped) parents, effectively skipping the commit.
skip_commit()
{
shift;
while [ -n "$1" ];
do
shift;
map "$1";
shift;
done;
}
# if you run 'git_commit_non_empty_tree "$@"' in a commit filter,
# it will skip commits that leave the tree untouched, commit the other.
git_commit_non_empty_tree()
{
if test $# = 3 && test "$1" = $(git rev-parse "$3^{tree}"); then
map "$3"
elif test $# = 1 && test "$1" = $EMPTY_TREE; then
:
else
git commit-tree "$@"
fi
}
# override die(): this version puts in an extra line break, so that
# the progress is still visible
die()
{
echo >&2
echo "$*" >&2
exit 1
}
EOF
)
eval "$functions"
finish_ident() {
# Ensure non-empty id name.
echo "case \"\$GIT_$1_NAME\" in \"\") GIT_$1_NAME=\"\${GIT_$1_EMAIL%%@*}\" && export GIT_$1_NAME;; esac"
# And make sure everything is exported.
echo "export GIT_$1_NAME"
echo "export GIT_$1_EMAIL"
echo "export GIT_$1_DATE"
}
set_ident () {
parse_ident_from_commit author AUTHOR committer COMMITTER
finish_ident AUTHOR
finish_ident COMMITTER
}
USAGE="[--setup <command>] [--subdirectory-filter <directory>] [--env-filter <command>]
[--tree-filter <command>] [--index-filter <command>]
[--parent-filter <command>] [--msg-filter <command>]
[--commit-filter <command>] [--tag-name-filter <command>]
[--original <namespace>]
[-d <directory>] [-f | --force] [--state-branch <branch>]
[--] [<rev-list options>...]"
OPTIONS_SPEC=
. git-sh-setup
if [ "$(is_bare_repository)" = false ]; then
require_clean_work_tree 'rewrite branches'
fi
tempdir=.git-rewrite
filter_setup=
filter_env=
filter_tree=
filter_index=
filter_parent=
filter_msg=cat
filter_commit=
filter_tag_name=
filter_subdir=
state_branch=
orig_namespace=refs/original/
force=
prune_empty=
remap_to_ancestor=
while :
do
case "$1" in
--)
shift
break
;;
--force|-f)
shift
force=t
continue
;;
--remap-to-ancestor)
# deprecated ($remap_to_ancestor is set now automatically)
shift
remap_to_ancestor=t
continue
;;
--prune-empty)
shift
prune_empty=t
continue
;;
-*)
;;
*)
break;
esac
# all switches take one argument
ARG="$1"
case "$#" in 1) usage ;; esac
shift
OPTARG="$1"
shift
case "$ARG" in
-d)
tempdir="$OPTARG"
;;
--setup)
filter_setup="$OPTARG"
;;
--subdirectory-filter)
filter_subdir="$OPTARG"
remap_to_ancestor=t
;;
--env-filter)
filter_env="$OPTARG"
;;
--tree-filter)
filter_tree="$OPTARG"
;;
--index-filter)
filter_index="$OPTARG"
;;
--parent-filter)
filter_parent="$OPTARG"
;;
--msg-filter)
filter_msg="$OPTARG"
;;
--commit-filter)
filter_commit="$functions; $OPTARG"
;;
--tag-name-filter)
filter_tag_name="$OPTARG"
;;
--original)
orig_namespace=$(expr "$OPTARG/" : '\(.*[^/]\)/*$')/
;;
--state-branch)
state_branch="$OPTARG"
;;
*)
usage
;;
esac
done
case "$prune_empty,$filter_commit" in
,)
filter_commit='git commit-tree "$@"';;
t,)
filter_commit="$functions;"' git_commit_non_empty_tree "$@"';;
,*)
;;
*)
die "Cannot set --prune-empty and --commit-filter at the same time"
esac
case "$force" in
t)
rm -rf "$tempdir"
;;
'')
test -d "$tempdir" &&
die "$tempdir already exists, please remove it"
esac
orig_dir=$(pwd)
mkdir -p "$tempdir/t" &&
tempdir="$(cd "$tempdir"; pwd)" &&
cd "$tempdir/t" &&
workdir="$(pwd)" ||
die ""
# Remove tempdir on exit
trap 'cd "$orig_dir"; rm -rf "$tempdir"' 0
ORIG_GIT_DIR="$GIT_DIR"
ORIG_GIT_WORK_TREE="$GIT_WORK_TREE"
ORIG_GIT_INDEX_FILE="$GIT_INDEX_FILE"
ORIG_GIT_AUTHOR_NAME="$GIT_AUTHOR_NAME"
ORIG_GIT_AUTHOR_EMAIL="$GIT_AUTHOR_EMAIL"
ORIG_GIT_AUTHOR_DATE="$GIT_AUTHOR_DATE"
ORIG_GIT_COMMITTER_NAME="$GIT_COMMITTER_NAME"
ORIG_GIT_COMMITTER_EMAIL="$GIT_COMMITTER_EMAIL"
ORIG_GIT_COMMITTER_DATE="$GIT_COMMITTER_DATE"
GIT_WORK_TREE=.
export GIT_DIR GIT_WORK_TREE
# Make sure refs/original is empty
git for-each-ref > "$tempdir"/backup-refs || exit
while read sha1 type name
do
case "$force,$name" in
,$orig_namespace*)
die "Cannot create a new backup.
A previous backup already exists in $orig_namespace
Force overwriting the backup with -f"
;;
t,$orig_namespace*)
git update-ref -d "$name" $sha1
;;
esac
done < "$tempdir"/backup-refs
# The refs should be updated if their heads were rewritten
git rev-parse --no-flags --revs-only --symbolic-full-name \
--default HEAD "$@" > "$tempdir"/raw-refs || exit
while read ref
do
case "$ref" in ^?*) continue ;; esac
if git rev-parse --verify "$ref"^0 >/dev/null 2>&1
then
echo "$ref"
else
warn "WARNING: not rewriting '$ref' (not a committish)"
fi
done >"$tempdir"/heads <"$tempdir"/raw-refs
test -s "$tempdir"/heads ||
die "You must specify a ref to rewrite."
GIT_INDEX_FILE="$(pwd)/../index"
export GIT_INDEX_FILE
# map old->new commit ids for rewriting parents
mkdir ../map || die "Could not create map/ directory"
if test -n "$state_branch"
then
state_commit=$(git rev-parse --no-flags --revs-only "$state_branch")
if test -n "$state_commit"
then
echo "Populating map from $state_branch ($state_commit)" 1>&2
perl -e'open(MAP, "-|", "git show $ARGV[0]:filter.map") or die;
while (<MAP>) {
m/(.*):(.*)/ or die;
open F, ">../map/$1" or die;
print F "$2" or die;
close(F) or die;
}
close(MAP) or die;' "$state_commit" \
|| die "Unable to load state from $state_branch:filter.map"
else
echo "Branch $state_branch does not exist. Will create" 1>&2
fi
fi
# we need "--" only if there are no path arguments in $@
nonrevs=$(git rev-parse --no-revs "$@") || exit
if test -z "$nonrevs"
then
dashdash=--
else
dashdash=
remap_to_ancestor=t
fi
git rev-parse --revs-only "$@" >../parse
case "$filter_subdir" in
"")
eval set -- "$(git rev-parse --sq --no-revs "$@")"
;;
*)
eval set -- "$(git rev-parse --sq --no-revs "$@" $dashdash \
"$filter_subdir")"
;;
esac
git rev-list --reverse --topo-order --default HEAD \
--parents --simplify-merges --stdin "$@" <../parse >../revs ||
die "Could not get the commits"
commits=$(wc -l <../revs | tr -d " ")
test $commits -eq 0 && die_with_status 2 "Found nothing to rewrite"
# Rewrite the commits
report_progress ()
{
if test -n "$progress" &&
test $git_filter_branch__commit_count -gt $next_sample_at
then
count=$git_filter_branch__commit_count
now=$(date +%s)
elapsed=$(($now - $start_timestamp))
remaining=$(( ($commits - $count) * $elapsed / $count ))
if test $elapsed -gt 0
then
next_sample_at=$(( ($elapsed + 1) * $count / $elapsed ))
else
next_sample_at=$(($next_sample_at + 1))
fi
progress=" ($elapsed seconds passed, remaining $remaining predicted)"
fi
printf "\rRewrite $commit ($count/$commits)$progress "
}
git_filter_branch__commit_count=0
progress= start_timestamp=
if date '+%s' 2>/dev/null | grep -q '^[0-9][0-9]*$'
then
next_sample_at=0
progress="dummy to ensure this is not empty"
start_timestamp=$(date '+%s')
fi
if test -n "$filter_index" ||
test -n "$filter_tree" ||
test -n "$filter_subdir"
then
need_index=t
else
need_index=
fi
eval "$filter_setup" < /dev/null ||
die "filter setup failed: $filter_setup"
while read commit parents; do
git_filter_branch__commit_count=$(($git_filter_branch__commit_count+1))
report_progress
test -f "$workdir"/../map/$commit && continue
case "$filter_subdir" in
"")
if test -n "$need_index"
then
GIT_ALLOW_NULL_SHA1=1 git read-tree -i -m $commit
fi
;;
*)
# The commit may not have the subdirectory at all
err=$(GIT_ALLOW_NULL_SHA1=1 \
git read-tree -i -m $commit:"$filter_subdir" 2>&1) || {
if ! git rev-parse -q --verify $commit:"$filter_subdir"
then
rm -f "$GIT_INDEX_FILE"
else
echo >&2 "$err"
false
fi
}
esac || die "Could not initialize the index"
GIT_COMMIT=$commit
export GIT_COMMIT
git cat-file commit "$commit" >../commit ||
die "Cannot read commit $commit"
eval "$(set_ident <../commit)" ||
die "setting author/committer failed for commit $commit"
eval "$filter_env" < /dev/null ||
die "env filter failed: $filter_env"
if [ "$filter_tree" ]; then
git checkout-index -f -u -a ||
die "Could not checkout the index"
# files that $commit removed are now still in the working tree;
# remove them, else they would be added again
git clean -d -q -f -x
eval "$filter_tree" < /dev/null ||
die "tree filter failed: $filter_tree"
(
git diff-index -r --name-only --ignore-submodules $commit -- &&
git ls-files --others
) > "$tempdir"/tree-state || exit
git update-index --add --replace --remove --stdin \
< "$tempdir"/tree-state || exit
fi
eval "$filter_index" < /dev/null ||
die "index filter failed: $filter_index"
parentstr=
for parent in $parents; do
for reparent in $(map "$parent"); do
case "$parentstr " in
*" -p $reparent "*)
;;
*)
parentstr="$parentstr -p $reparent"
;;
esac
done
done
if [ "$filter_parent" ]; then
parentstr="$(echo "$parentstr" | eval "$filter_parent")" ||
die "parent filter failed: $filter_parent"
fi
{
while IFS='' read -r header_line && test -n "$header_line"
do
# skip header lines...
:;
done
# and output the actual commit message
cat
} <../commit |
eval "$filter_msg" > ../message ||
die "msg filter failed: $filter_msg"
if test -n "$need_index"
then
tree=$(git write-tree)
else
tree=$(git rev-parse "$commit^{tree}")
fi
workdir=$workdir /bin/sh -c "$filter_commit" "git commit-tree" \
"$tree" $parentstr < ../message > ../map/$commit ||
die "could not write rewritten commit"
done <../revs
# If we are filtering for paths, as in the case of a subdirectory
# filter, it is possible that a specified head is not in the set of
# rewritten commits, because it was pruned by the revision walker.
# Ancestor remapping fixes this by mapping these heads to the unique
# nearest ancestor that survived the pruning.
if test "$remap_to_ancestor" = t
then
while read ref
do
sha1=$(git rev-parse "$ref"^0)
test -f "$workdir"/../map/$sha1 && continue
ancestor=$(git rev-list --simplify-merges -1 "$ref" "$@")
test "$ancestor" && echo $(map $ancestor) >> "$workdir"/../map/$sha1
done < "$tempdir"/heads
fi
# Finally update the refs
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
echo
while read ref
do
# avoid rewriting a ref twice
test -f "$orig_namespace$ref" && continue
sha1=$(git rev-parse "$ref"^0)
rewritten=$(map $sha1)
test $sha1 = "$rewritten" &&
warn "WARNING: Ref '$ref' is unchanged" &&
continue
case "$rewritten" in
'')
echo "Ref '$ref' was deleted"
git update-ref -m "filter-branch: delete" -d "$ref" $sha1 ||
die "Could not delete $ref"
;;
$_x40)
echo "Ref '$ref' was rewritten"
if ! git update-ref -m "filter-branch: rewrite" \
"$ref" $rewritten $sha1 2>/dev/null; then
if test $(git cat-file -t "$ref") = tag; then
if test -z "$filter_tag_name"; then
warn "WARNING: You said to rewrite tagged commits, but not the corresponding tag."
warn "WARNING: Perhaps use '--tag-name-filter cat' to rewrite the tag."
fi
else
die "Could not rewrite $ref"
fi
fi
;;
*)
# NEEDSWORK: possibly add -Werror, making this an error
warn "WARNING: '$ref' was rewritten into multiple commits:"
warn "$rewritten"
warn "WARNING: Ref '$ref' points to the first one now."
rewritten=$(echo "$rewritten" | head -n 1)
git update-ref -m "filter-branch: rewrite to first" \
"$ref" $rewritten $sha1 ||
die "Could not rewrite $ref"
;;
esac
git update-ref -m "filter-branch: backup" "$orig_namespace$ref" $sha1 ||
exit
done < "$tempdir"/heads
# TODO: This should possibly go, with the semantics that all positive given
# refs are updated, and their original heads stored in refs/original/
# Filter tags
if [ "$filter_tag_name" ]; then
git for-each-ref --format='%(objectname) %(objecttype) %(refname)' refs/tags |
while read sha1 type ref; do
ref="${ref#refs/tags/}"
# XXX: Rewrite tagged trees as well?
if [ "$type" != "commit" -a "$type" != "tag" ]; then
continue;
fi
if [ "$type" = "tag" ]; then
# Dereference to a commit
sha1t="$sha1"
sha1="$(git rev-parse -q "$sha1"^{commit})" || continue
fi
[ -f "../map/$sha1" ] || continue
new_sha1="$(cat "../map/$sha1")"
GIT_COMMIT="$sha1"
export GIT_COMMIT
new_ref="$(echo "$ref" | eval "$filter_tag_name")" ||
die "tag name filter failed: $filter_tag_name"
echo "$ref -> $new_ref ($sha1 -> $new_sha1)"
if [ "$type" = "tag" ]; then
new_sha1=$( ( printf 'object %s\ntype commit\ntag %s\n' \
"$new_sha1" "$new_ref"
git cat-file tag "$ref" |
sed -n \
-e '1,/^$/{
/^object /d
/^type /d
/^tag /d
}' \
-e '/^-----BEGIN PGP SIGNATURE-----/q' \
-e 'p' ) |
git hash-object -t tag -w --stdin) ||
die "Could not create new tag object for $ref"
if git cat-file tag "$ref" | \
sane_grep '^-----BEGIN PGP SIGNATURE-----' >/dev/null 2>&1
then
warn "gpg signature stripped from tag object $sha1t"
fi
fi
git update-ref "refs/tags/$new_ref" "$new_sha1" ||
die "Could not write tag $new_ref"
done
fi
unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE
unset GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
unset GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL GIT_COMMITTER_DATE
test -z "$ORIG_GIT_DIR" || {
GIT_DIR="$ORIG_GIT_DIR" && export GIT_DIR
}
test -z "$ORIG_GIT_WORK_TREE" || {
GIT_WORK_TREE="$ORIG_GIT_WORK_TREE" &&
export GIT_WORK_TREE
}
test -z "$ORIG_GIT_INDEX_FILE" || {
GIT_INDEX_FILE="$ORIG_GIT_INDEX_FILE" &&
export GIT_INDEX_FILE
}
test -z "$ORIG_GIT_AUTHOR_NAME" || {
GIT_AUTHOR_NAME="$ORIG_GIT_AUTHOR_NAME" &&
export GIT_AUTHOR_NAME
}
test -z "$ORIG_GIT_AUTHOR_EMAIL" || {
GIT_AUTHOR_EMAIL="$ORIG_GIT_AUTHOR_EMAIL" &&
export GIT_AUTHOR_EMAIL
}
test -z "$ORIG_GIT_AUTHOR_DATE" || {
GIT_AUTHOR_DATE="$ORIG_GIT_AUTHOR_DATE" &&
export GIT_AUTHOR_DATE
}
test -z "$ORIG_GIT_COMMITTER_NAME" || {
GIT_COMMITTER_NAME="$ORIG_GIT_COMMITTER_NAME" &&
export GIT_COMMITTER_NAME
}
test -z "$ORIG_GIT_COMMITTER_EMAIL" || {
GIT_COMMITTER_EMAIL="$ORIG_GIT_COMMITTER_EMAIL" &&
export GIT_COMMITTER_EMAIL
}
test -z "$ORIG_GIT_COMMITTER_DATE" || {
GIT_COMMITTER_DATE="$ORIG_GIT_COMMITTER_DATE" &&
export GIT_COMMITTER_DATE
}
if test -n "$state_branch"
then
echo "Saving rewrite state to $state_branch" 1>&2
state_blob=$(
perl -e'opendir D, "../map" or die;
open H, "|-", "git hash-object -w --stdin" or die;
foreach (sort readdir(D)) {
next if m/^\.\.?$/;
open F, "<../map/$_" or die;
chomp($f = <F>);
print H "$_:$f\n" or die;
}
close(H) or die;' || die "Unable to save state")
state_tree=$(printf '100644 blob %s\tfilter.map\n' "$state_blob" | git mktree)
if test -n "$state_commit"
then
state_commit=$(echo "Sync" | git commit-tree "$state_tree" -p "$state_commit")
else
state_commit=$(echo "Sync" | git commit-tree "$state_tree" )
fi
git update-ref "$state_branch" "$state_commit"
fi
cd "$orig_dir"
rm -rf "$tempdir"
trap - 0
if [ "$(is_bare_repository)" = false ]; then
git read-tree -u -m HEAD || exit
fi
exit 0

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,25 @@
#!/bin/sh
# Tcl ignores the next line -*- tcl -*- \
exec wish "$0" -- "$@"
if { $argc >=2 && [lindex $argv 0] == "--working-dir" } {
set workdir [lindex $argv 1]
cd $workdir
if {[lindex [file split $workdir] end] eq {.git}} {
# Workaround for Explorer right click "Git GUI Here" on .git/
cd ..
}
set argv [lrange $argv 2 end]
incr argc -2
}
set basedir [file dirname \
[file dirname \
[file dirname [info script]]]]
set bindir [file join $basedir bin]
set bindir "$bindir;[file join $basedir mingw bin]"
regsub -all ";" $bindir "\\;" bindir
set env(PATH) "$bindir;$env(PATH)"
unset bindir
source [file join [file dirname [info script]] git-gui.tcl]

View File

@ -0,0 +1,66 @@
#!/bin/sh
# Tcl ignores the next line -*- tcl -*- \
exec wish "$0" -- "$@"
# This is a trivial implementation of an SSH_ASKPASS handler.
# Git-gui uses this script if none are already configured.
package require Tk
set answer {}
set yesno 0
set rc 255
if {$argc < 1} {
set prompt "Enter your OpenSSH passphrase:"
} else {
set prompt [join $argv " "]
if {[regexp -nocase {\(yes\/no\)\?\s*$} $prompt]} {
set yesno 1
}
}
message .m -text $prompt -justify center -aspect 4000
pack .m -side top -fill x -padx 20 -pady 20 -expand 1
entry .e -textvariable answer -width 50
pack .e -side top -fill x -padx 10 -pady 10
if {!$yesno} {
.e configure -show "*"
}
frame .b
button .b.ok -text OK -command finish
button .b.cancel -text Cancel -command cancel
pack .b.ok -side left -expand 1
pack .b.cancel -side right -expand 1
pack .b -side bottom -fill x -padx 10 -pady 10
bind . <Visibility> {focus -force .e}
bind . <Key-Return> [list .b.ok invoke]
bind . <Key-Escape> [list .b.cancel invoke]
bind . <Destroy> {set rc $rc}
proc cancel {} {
set ::rc 255
}
proc finish {} {
if {$::yesno} {
if {$::answer ne "yes" && $::answer ne "no"} {
tk_messageBox -icon error -title "Error" -type ok \
-message "Only 'yes' or 'no' input allowed."
return
}
}
puts $::answer
set ::rc 0
}
wm title . "OpenSSH"
tk::PlaceWindow .
vwait rc
exit $rc

View File

@ -0,0 +1,68 @@
#!/bin/sh
# Tcl ignores the next line -*- tcl -*- \
exec wish "$0" -- "$@"
# This is an implementation of a simple yes no dialog
# which is injected into the git commandline by git gui
# in case a yesno question needs to be answered.
set NS {}
set use_ttk [package vsatisfies [package provide Tk] 8.5]
if {$use_ttk} {
set NS ttk
}
set title "Question?"
if {$argc < 1} {
puts stderr "Usage: $argv0 <question>"
exit 1
} else {
if {$argc > 2 && [lindex $argv 0] == "--title"} {
set title [lindex $argv 1]
set argv [lreplace $argv 0 1]
}
set prompt [join $argv " "]
}
${NS}::frame .t
${NS}::label .t.m -text $prompt -justify center -width 400px
.t.m configure -wraplength 400px
pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1
pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1
${NS}::frame .b
${NS}::frame .b.left -width 200
${NS}::button .b.yes -text Yes -command yes
${NS}::button .b.no -text No -command no
pack .b.left -side left -expand 1 -fill x
pack .b.yes -side left -expand 1
pack .b.no -side right -expand 1 -ipadx 5
pack .b -side bottom -fill x -ipadx 20 -ipady 15
bind . <Key-Return> {exit 0}
bind . <Key-Escape> {exit 1}
proc no {} {
exit 1
}
proc yes {} {
exit 0
}
if {$::tcl_platform(platform) eq {windows}} {
set icopath [file dirname [file normalize $argv0]]
if {[file tail $icopath] eq {git-core}} {
set icopath [file dirname $icopath]
}
set icopath [file dirname $icopath]
set icopath [file join $icopath share git git-for-windows.ico]
if {[file exists $icopath]} {
wm iconbitmap . -default $icopath
}
}
wm title . $title
tk::PlaceWindow .

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,789 @@
#!/bin/sh
#
# Copyright (c) 2006 Eric Wong
#
PERL='/usr/bin/perl'
OPTIONS_KEEPDASHDASH=
OPTIONS_STUCKLONG=
OPTIONS_SPEC="\
git instaweb [options] (--start | --stop | --restart)
--
l,local only bind on 127.0.0.1
p,port= the port to bind to
d,httpd= the command to launch
b,browser= the browser to launch
m,module-path= the module path (only needed for apache2)
Action
stop stop the web server
start start the web server
restart restart the web server
"
SUBDIRECTORY_OK=Yes
. git-sh-setup
fqgitdir="$GIT_DIR"
local="$(git config --bool --get instaweb.local)"
httpd="$(git config --get instaweb.httpd)"
root="$(git config --get instaweb.gitwebdir)"
port=$(git config --get instaweb.port)
module_path="$(git config --get instaweb.modulepath)"
action="browse"
conf="$GIT_DIR/gitweb/httpd.conf"
# Defaults:
# if installed, it doesn't need further configuration (module_path)
test -z "$httpd" && httpd='lighttpd -f'
# Default is /mingw64/share/gitweb
test -z "$root" && root='/mingw64/share/gitweb'
# any untaken local port will do...
test -z "$port" && port=1234
resolve_full_httpd () {
case "$httpd" in
*apache2*|*lighttpd*|*httpd*)
# yes, *httpd* covers *lighttpd* above, but it is there for clarity
# ensure that the apache2/lighttpd command ends with "-f"
if ! echo "$httpd" | sane_grep -- '-f *$' >/dev/null 2>&1
then
httpd="$httpd -f"
fi
;;
*plackup*)
# server is started by running via generated gitweb.psgi in $fqgitdir/gitweb
full_httpd="$fqgitdir/gitweb/gitweb.psgi"
httpd_only="${httpd%% *}" # cut on first space
return
;;
*webrick*)
# server is started by running via generated webrick.rb in
# $fqgitdir/gitweb
full_httpd="$fqgitdir/gitweb/webrick.rb"
httpd_only="${httpd%% *}" # cut on first space
return
;;
*python*)
# server is started by running via generated gitweb.py in
# $fqgitdir/gitweb
full_httpd="$fqgitdir/gitweb/gitweb.py"
httpd_only="${httpd%% *}" # cut on first space
return
;;
esac
httpd_only="$(echo $httpd | cut -f1 -d' ')"
if case "$httpd_only" in /*) : ;; *) which $httpd_only >/dev/null 2>&1;; esac
then
full_httpd=$httpd
else
# many httpds are installed in /usr/sbin or /usr/local/sbin
# these days and those are not in most users $PATHs
# in addition, we may have generated a server script
# in $fqgitdir/gitweb.
for i in /usr/local/sbin /usr/sbin "$root" "$fqgitdir/gitweb"
do
if test -x "$i/$httpd_only"
then
full_httpd=$i/$httpd
return
fi
done
echo >&2 "$httpd_only not found. Install $httpd_only or use" \
"--httpd to specify another httpd daemon."
exit 1
fi
}
start_httpd () {
if test -f "$fqgitdir/pid"; then
say "Instance already running. Restarting..."
stop_httpd
fi
# here $httpd should have a meaningful value
resolve_full_httpd
mkdir -p "$fqgitdir/gitweb/$httpd_only"
conf="$fqgitdir/gitweb/$httpd_only.conf"
# generate correct config file if it doesn't exist
test -f "$conf" || configure_httpd
test -f "$fqgitdir/gitweb/gitweb_config.perl" || gitweb_conf
# don't quote $full_httpd, there can be arguments to it (-f)
case "$httpd" in
*mongoose*|*plackup*|*python*)
#These servers don't have a daemon mode so we'll have to fork it
$full_httpd "$conf" &
#Save the pid before doing anything else (we'll print it later)
pid=$!
if test $? != 0; then
echo "Could not execute http daemon $httpd."
exit 1
fi
cat > "$fqgitdir/pid" <<EOF
$pid
EOF
;;
*)
$full_httpd "$conf"
if test $? != 0; then
echo "Could not execute http daemon $httpd."
exit 1
fi
;;
esac
}
stop_httpd () {
test -f "$fqgitdir/pid" && kill $(cat "$fqgitdir/pid")
rm -f "$fqgitdir/pid"
}
httpd_is_ready () {
"$PERL" -MIO::Socket::INET -e "
local \$| = 1; # turn on autoflush
exit if (IO::Socket::INET->new('127.0.0.1:$port'));
print 'Waiting for \'$httpd\' to start ..';
do {
print '.';
sleep(1);
} until (IO::Socket::INET->new('127.0.0.1:$port'));
print qq! (done)\n!;
"
}
while test $# != 0
do
case "$1" in
--stop|stop)
action="stop"
;;
--start|start)
action="start"
;;
--restart|restart)
action="restart"
;;
-l|--local)
local=true
;;
-d|--httpd)
shift
httpd="$1"
;;
-b|--browser)
shift
browser="$1"
;;
-p|--port)
shift
port="$1"
;;
-m|--module-path)
shift
module_path="$1"
;;
--)
;;
*)
usage
;;
esac
shift
done
mkdir -p "$GIT_DIR/gitweb/tmp"
GIT_EXEC_PATH="$(git --exec-path)"
GIT_DIR="$fqgitdir"
GITWEB_CONFIG="$fqgitdir/gitweb/gitweb_config.perl"
export GIT_EXEC_PATH GIT_DIR GITWEB_CONFIG
webrick_conf () {
# webrick seems to have no way of passing arbitrary environment
# variables to the underlying CGI executable, so we wrap the
# actual gitweb.cgi using a shell script to force it
wrapper="$fqgitdir/gitweb/$httpd/wrapper.sh"
cat > "$wrapper" <<EOF
#!/bin/sh
# we use this shell script wrapper around the real gitweb.cgi since
# there appears to be no other way to pass arbitrary environment variables
# into the CGI process
GIT_EXEC_PATH=$GIT_EXEC_PATH GIT_DIR=$GIT_DIR GITWEB_CONFIG=$GITWEB_CONFIG
export GIT_EXEC_PATH GIT_DIR GITWEB_CONFIG
exec $root/gitweb.cgi
EOF
chmod +x "$wrapper"
# This assumes _ruby_ is in the user's $PATH. that's _one_
# portable way to run ruby, which could be installed anywhere, really.
# generate a standalone server script in $fqgitdir/gitweb.
cat >"$fqgitdir/gitweb/$httpd.rb" <<EOF
#!/usr/bin/env ruby
require 'webrick'
require 'logger'
options = {
:Port => $port,
:DocumentRoot => "$root",
:Logger => Logger.new('$fqgitdir/gitweb/error.log'),
:AccessLog => [
[ Logger.new('$fqgitdir/gitweb/access.log'),
WEBrick::AccessLog::COMBINED_LOG_FORMAT ]
],
:DirectoryIndex => ["gitweb.cgi"],
:CGIInterpreter => "$wrapper",
:StartCallback => lambda do
File.open("$fqgitdir/pid", "w") { |f| f.puts Process.pid }
end,
:ServerType => WEBrick::Daemon,
}
options[:BindAddress] = '127.0.0.1' if "$local" == "true"
server = WEBrick::HTTPServer.new(options)
['INT', 'TERM'].each do |signal|
trap(signal) {server.shutdown}
end
server.start
EOF
chmod +x "$fqgitdir/gitweb/$httpd.rb"
# configuration is embedded in server script file, webrick.rb
rm -f "$conf"
}
lighttpd_conf () {
cat > "$conf" <<EOF
server.document-root = "$root"
server.port = $port
server.modules = ( "mod_setenv", "mod_cgi" )
server.indexfiles = ( "gitweb.cgi" )
server.pid-file = "$fqgitdir/pid"
server.errorlog = "$fqgitdir/gitweb/$httpd_only/error.log"
# to enable, add "mod_access", "mod_accesslog" to server.modules
# variable above and uncomment this
#accesslog.filename = "$fqgitdir/gitweb/$httpd_only/access.log"
setenv.add-environment = ( "PATH" => env.PATH, "GITWEB_CONFIG" => env.GITWEB_CONFIG )
cgi.assign = ( ".cgi" => "" )
# mimetype mapping
mimetype.assign = (
".pdf" => "application/pdf",
".sig" => "application/pgp-signature",
".spl" => "application/futuresplash",
".class" => "application/octet-stream",
".ps" => "application/postscript",
".torrent" => "application/x-bittorrent",
".dvi" => "application/x-dvi",
".gz" => "application/x-gzip",
".pac" => "application/x-ns-proxy-autoconfig",
".swf" => "application/x-shockwave-flash",
".tar.gz" => "application/x-tgz",
".tgz" => "application/x-tgz",
".tar" => "application/x-tar",
".zip" => "application/zip",
".mp3" => "audio/mpeg",
".m3u" => "audio/x-mpegurl",
".wma" => "audio/x-ms-wma",
".wax" => "audio/x-ms-wax",
".ogg" => "application/ogg",
".wav" => "audio/x-wav",
".gif" => "image/gif",
".jpg" => "image/jpeg",
".jpeg" => "image/jpeg",
".png" => "image/png",
".xbm" => "image/x-xbitmap",
".xpm" => "image/x-xpixmap",
".xwd" => "image/x-xwindowdump",
".css" => "text/css",
".html" => "text/html",
".htm" => "text/html",
".js" => "text/javascript",
".asc" => "text/plain",
".c" => "text/plain",
".cpp" => "text/plain",
".log" => "text/plain",
".conf" => "text/plain",
".text" => "text/plain",
".txt" => "text/plain",
".dtd" => "text/xml",
".xml" => "text/xml",
".mpeg" => "video/mpeg",
".mpg" => "video/mpeg",
".mov" => "video/quicktime",
".qt" => "video/quicktime",
".avi" => "video/x-msvideo",
".asf" => "video/x-ms-asf",
".asx" => "video/x-ms-asf",
".wmv" => "video/x-ms-wmv",
".bz2" => "application/x-bzip",
".tbz" => "application/x-bzip-compressed-tar",
".tar.bz2" => "application/x-bzip-compressed-tar",
"" => "text/plain"
)
EOF
test x"$local" = xtrue && echo 'server.bind = "127.0.0.1"' >> "$conf"
}
apache2_conf () {
for candidate in \
/etc/httpd \
/usr/lib/apache2 \
/usr/lib/httpd ;
do
if test -d "$candidate/modules"
then
module_path="$candidate/modules"
break
fi
done
bind=
test x"$local" = xtrue && bind='127.0.0.1:'
echo 'text/css css' > "$fqgitdir/mime.types"
cat > "$conf" <<EOF
ServerName "git-instaweb"
ServerRoot "$root"
DocumentRoot "$root"
ErrorLog "$fqgitdir/gitweb/$httpd_only/error.log"
CustomLog "$fqgitdir/gitweb/$httpd_only/access.log" combined
PidFile "$fqgitdir/pid"
Listen $bind$port
EOF
for mod in mpm_event mpm_prefork mpm_worker
do
if test -e $module_path/mod_${mod}.so
then
echo "LoadModule ${mod}_module " \
"$module_path/mod_${mod}.so" >> "$conf"
# only one mpm module permitted
break
fi
done
for mod in mime dir env log_config authz_core unixd
do
if test -e $module_path/mod_${mod}.so
then
echo "LoadModule ${mod}_module " \
"$module_path/mod_${mod}.so" >> "$conf"
fi
done
cat >> "$conf" <<EOF
TypesConfig "$fqgitdir/mime.types"
DirectoryIndex gitweb.cgi
EOF
# check to see if Dennis Stosberg's mod_perl compatibility patch
# (<20060621130708.Gcbc6e5c@leonov.stosberg.net>) has been applied
if test -f "$module_path/mod_perl.so" &&
sane_grep 'MOD_PERL' "$root/gitweb.cgi" >/dev/null
then
# favor mod_perl if available
cat >> "$conf" <<EOF
LoadModule perl_module $module_path/mod_perl.so
PerlPassEnv GIT_DIR
PerlPassEnv GIT_EXEC_PATH
PerlPassEnv GITWEB_CONFIG
<Location /gitweb.cgi>
SetHandler perl-script
PerlResponseHandler ModPerl::Registry
PerlOptions +ParseHeaders
Options +ExecCGI
</Location>
EOF
else
# plain-old CGI
resolve_full_httpd
list_mods=$(echo "$full_httpd" | sed 's/-f$/-l/')
$list_mods | sane_grep 'mod_cgi\.c' >/dev/null 2>&1 || \
if test -f "$module_path/mod_cgi.so"
then
echo "LoadModule cgi_module $module_path/mod_cgi.so" >> "$conf"
else
$list_mods | grep 'mod_cgid\.c' >/dev/null 2>&1 || \
if test -f "$module_path/mod_cgid.so"
then
echo "LoadModule cgid_module $module_path/mod_cgid.so" \
>> "$conf"
else
echo "You have no CGI support!"
exit 2
fi
echo "ScriptSock logs/gitweb.sock" >> "$conf"
fi
cat >> "$conf" <<EOF
PassEnv GIT_DIR
PassEnv GIT_EXEC_PATH
PassEnv GITWEB_CONFIG
AddHandler cgi-script .cgi
<Location /gitweb.cgi>
Options +ExecCGI
</Location>
EOF
fi
}
mongoose_conf() {
cat > "$conf" <<EOF
# Mongoose web server configuration file.
# Lines starting with '#' and empty lines are ignored.
# For detailed description of every option, visit
# http://code.google.com/p/mongoose/wiki/MongooseManual
root $root
ports $port
index_files gitweb.cgi
#ssl_cert $fqgitdir/gitweb/ssl_cert.pem
error_log $fqgitdir/gitweb/$httpd_only/error.log
access_log $fqgitdir/gitweb/$httpd_only/access.log
#cgi setup
cgi_env PATH=$PATH,GIT_DIR=$GIT_DIR,GIT_EXEC_PATH=$GIT_EXEC_PATH,GITWEB_CONFIG=$GITWEB_CONFIG
cgi_interp $PERL
cgi_ext cgi,pl
# mimetype mapping
mime_types .gz=application/x-gzip,.tar.gz=application/x-tgz,.tgz=application/x-tgz,.tar=application/x-tar,.zip=application/zip,.gif=image/gif,.jpg=image/jpeg,.jpeg=image/jpeg,.png=image/png,.css=text/css,.html=text/html,.htm=text/html,.js=text/javascript,.c=text/plain,.cpp=text/plain,.log=text/plain,.conf=text/plain,.text=text/plain,.txt=text/plain,.dtd=text/xml,.bz2=application/x-bzip,.tbz=application/x-bzip-compressed-tar,.tar.bz2=application/x-bzip-compressed-tar
EOF
}
plackup_conf () {
# generate a standalone 'plackup' server script in $fqgitdir/gitweb
# with embedded configuration; it does not use "$conf" file
cat > "$fqgitdir/gitweb/gitweb.psgi" <<EOF
#!$PERL
# gitweb - simple web interface to track changes in git repositories
# PSGI wrapper and server starter (see http://plackperl.org)
use strict;
use IO::Handle;
use Plack::MIME;
use Plack::Builder;
use Plack::App::WrapCGI;
use CGI::Emulate::PSGI 0.07; # minimum version required to work with gitweb
# mimetype mapping (from lighttpd_conf)
Plack::MIME->add_type(
".pdf" => "application/pdf",
".sig" => "application/pgp-signature",
".spl" => "application/futuresplash",
".class" => "application/octet-stream",
".ps" => "application/postscript",
".torrent" => "application/x-bittorrent",
".dvi" => "application/x-dvi",
".gz" => "application/x-gzip",
".pac" => "application/x-ns-proxy-autoconfig",
".swf" => "application/x-shockwave-flash",
".tar.gz" => "application/x-tgz",
".tgz" => "application/x-tgz",
".tar" => "application/x-tar",
".zip" => "application/zip",
".mp3" => "audio/mpeg",
".m3u" => "audio/x-mpegurl",
".wma" => "audio/x-ms-wma",
".wax" => "audio/x-ms-wax",
".ogg" => "application/ogg",
".wav" => "audio/x-wav",
".gif" => "image/gif",
".jpg" => "image/jpeg",
".jpeg" => "image/jpeg",
".png" => "image/png",
".xbm" => "image/x-xbitmap",
".xpm" => "image/x-xpixmap",
".xwd" => "image/x-xwindowdump",
".css" => "text/css",
".html" => "text/html",
".htm" => "text/html",
".js" => "text/javascript",
".asc" => "text/plain",
".c" => "text/plain",
".cpp" => "text/plain",
".log" => "text/plain",
".conf" => "text/plain",
".text" => "text/plain",
".txt" => "text/plain",
".dtd" => "text/xml",
".xml" => "text/xml",
".mpeg" => "video/mpeg",
".mpg" => "video/mpeg",
".mov" => "video/quicktime",
".qt" => "video/quicktime",
".avi" => "video/x-msvideo",
".asf" => "video/x-ms-asf",
".asx" => "video/x-ms-asf",
".wmv" => "video/x-ms-wmv",
".bz2" => "application/x-bzip",
".tbz" => "application/x-bzip-compressed-tar",
".tar.bz2" => "application/x-bzip-compressed-tar",
"" => "text/plain"
);
my \$app = builder {
# to be able to override \$SIG{__WARN__} to log build time warnings
use CGI::Carp; # it sets \$SIG{__WARN__} itself
my \$logdir = "$fqgitdir/gitweb/$httpd_only";
open my \$access_log_fh, '>>', "\$logdir/access.log"
or die "Couldn't open access log '\$logdir/access.log': \$!";
open my \$error_log_fh, '>>', "\$logdir/error.log"
or die "Couldn't open error log '\$logdir/error.log': \$!";
\$access_log_fh->autoflush(1);
\$error_log_fh->autoflush(1);
# redirect build time warnings to error.log
\$SIG{'__WARN__'} = sub {
my \$msg = shift;
# timestamp warning like in CGI::Carp::warn
my \$stamp = CGI::Carp::stamp();
\$msg =~ s/^/\$stamp/gm;
print \$error_log_fh \$msg;
};
# write errors to error.log, access to access.log
enable 'AccessLog',
format => "combined",
logger => sub { print \$access_log_fh @_; };
enable sub {
my \$app = shift;
sub {
my \$env = shift;
\$env->{'psgi.errors'} = \$error_log_fh;
\$app->(\$env);
}
};
# gitweb currently doesn't work with $SIG{CHLD} set to 'IGNORE',
# because it uses 'close $fd or die...' on piped filehandle $fh
# (which causes the parent process to wait for child to finish).
enable_if { \$SIG{'CHLD'} eq 'IGNORE' } sub {
my \$app = shift;
sub {
my \$env = shift;
local \$SIG{'CHLD'} = 'DEFAULT';
local \$SIG{'CLD'} = 'DEFAULT';
\$app->(\$env);
}
};
# serve static files, i.e. stylesheet, images, script
enable 'Static',
path => sub { m!\.(js|css|png)\$! && s!^/gitweb/!! },
root => "$root/",
encoding => 'utf-8'; # encoding for 'text/plain' files
# convert CGI application to PSGI app
Plack::App::WrapCGI->new(script => "$root/gitweb.cgi")->to_app;
};
# make it runnable as standalone app,
# like it would be run via 'plackup' utility
if (caller) {
return \$app;
} else {
require Plack::Runner;
my \$runner = Plack::Runner->new();
\$runner->parse_options(qw(--env deployment --port $port),
"$local" ? qw(--host 127.0.0.1) : ());
\$runner->run(\$app);
}
__END__
EOF
chmod a+x "$fqgitdir/gitweb/gitweb.psgi"
# configuration is embedded in server script file, gitweb.psgi
rm -f "$conf"
}
python_conf() {
# Python's builtin http.server and its CGI support is very limited.
# CGI handler is capable of running CGI script only from inside a directory.
# Trying to set cgi_directories=["/"] will add double slash to SCRIPT_NAME
# and that in turn breaks gitweb's relative link generation.
# create a simple web root where $fqgitdir/gitweb/$httpd_only is our root
mkdir -p "$fqgitdir/gitweb/$httpd_only/cgi-bin"
# Python http.server follows the symlinks
ln -sf "$root/gitweb.cgi" "$fqgitdir/gitweb/$httpd_only/cgi-bin/gitweb.cgi"
ln -sf "$root/static" "$fqgitdir/gitweb/$httpd_only/"
# generate a standalone 'python http.server' script in $fqgitdir/gitweb
# This asumes that python is in user's $PATH
# This script is Python 2 and 3 compatible
cat > "$fqgitdir/gitweb/gitweb.py" <<EOF
#!/usr/bin/env python
import os
import sys
# Open log file in line buffering mode
accesslogfile = open("$fqgitdir/gitweb/access.log", 'a', buffering=1)
errorlogfile = open("$fqgitdir/gitweb/error.log", 'a', buffering=1)
# and replace our stdout and stderr with log files
# also do a lowlevel duplicate of the logfile file descriptors so that
# our CGI child process writes any stderr warning also to the log file
_orig_stdout_fd = sys.stdout.fileno()
sys.stdout.close()
os.dup2(accesslogfile.fileno(), _orig_stdout_fd)
sys.stdout = accesslogfile
_orig_stderr_fd = sys.stderr.fileno()
sys.stderr.close()
os.dup2(errorlogfile.fileno(), _orig_stderr_fd)
sys.stderr = errorlogfile
from functools import partial
if sys.version_info < (3, 0): # Python 2
from CGIHTTPServer import CGIHTTPRequestHandler
from BaseHTTPServer import HTTPServer as ServerClass
else: # Python 3
from http.server import CGIHTTPRequestHandler
from http.server import HTTPServer as ServerClass
# Those environment variables will be passed to the cgi script
os.environ.update({
"GIT_EXEC_PATH": "$GIT_EXEC_PATH",
"GIT_DIR": "$GIT_DIR",
"GITWEB_CONFIG": "$GITWEB_CONFIG"
})
class GitWebRequestHandler(CGIHTTPRequestHandler):
def log_message(self, format, *args):
# Write access logs to stdout
sys.stdout.write("%s - - [%s] %s\n" %
(self.address_string(),
self.log_date_time_string(),
format%args))
def do_HEAD(self):
self.redirect_path()
CGIHTTPRequestHandler.do_HEAD(self)
def do_GET(self):
if self.path == "/":
self.send_response(303, "See Other")
self.send_header("Location", "/cgi-bin/gitweb.cgi")
self.end_headers()
return
self.redirect_path()
CGIHTTPRequestHandler.do_GET(self)
def do_POST(self):
self.redirect_path()
CGIHTTPRequestHandler.do_POST(self)
# rewrite path of every request that is not gitweb.cgi to out of cgi-bin
def redirect_path(self):
if not self.path.startswith("/cgi-bin/gitweb.cgi"):
self.path = self.path.replace("/cgi-bin/", "/")
# gitweb.cgi is the only thing that is ever going to be run here.
# Ignore everything else
def is_cgi(self):
result = False
if self.path.startswith('/cgi-bin/gitweb.cgi'):
result = CGIHTTPRequestHandler.is_cgi(self)
return result
bind = "127.0.0.1"
if "$local" == "true":
bind = "0.0.0.0"
# Set our http root directory
# This is a work around for a missing directory argument in older Python versions
# as this was added to SimpleHTTPRequestHandler in Python 3.7
os.chdir("$fqgitdir/gitweb/$httpd_only/")
GitWebRequestHandler.protocol_version = "HTTP/1.0"
httpd = ServerClass((bind, $port), GitWebRequestHandler)
sa = httpd.socket.getsockname()
print("Serving HTTP on", sa[0], "port", sa[1], "...")
httpd.serve_forever()
EOF
chmod a+x "$fqgitdir/gitweb/gitweb.py"
}
gitweb_conf() {
cat > "$fqgitdir/gitweb/gitweb_config.perl" <<EOF
#!/usr/bin/perl
our \$projectroot = "$(dirname "$fqgitdir")";
our \$git_temp = "$fqgitdir/gitweb/tmp";
our \$projects_list = \$projectroot;
\$feature{'remote_heads'}{'default'} = [1];
EOF
}
configure_httpd() {
case "$httpd" in
*lighttpd*)
lighttpd_conf
;;
*apache2*|*httpd*)
apache2_conf
;;
webrick)
webrick_conf
;;
*mongoose*)
mongoose_conf
;;
*plackup*)
plackup_conf
;;
*python*)
python_conf
;;
*)
echo "Unknown httpd specified: $httpd"
exit 1
;;
esac
}
case "$action" in
stop)
stop_httpd
exit 0
;;
start)
start_httpd
exit 0
;;
restart)
stop_httpd
start_httpd
exit 0
;;
esac
gitweb_conf
resolve_full_httpd
mkdir -p "$fqgitdir/gitweb/$httpd_only"
conf="$fqgitdir/gitweb/$httpd_only.conf"
configure_httpd
start_httpd
url=http://127.0.0.1:$port
if test -n "$browser"; then
httpd_is_ready && git web--browse -b "$browser" $url || echo $url
else
httpd_is_ready && git web--browse -c "instaweb.browser" $url || echo $url
fi

View File

@ -0,0 +1,745 @@
#!/bin/sh
#
# Copyright (c) 2005 Junio C Hamano.
#
SUBDIRECTORY_OK=Yes
OPTIONS_KEEPDASHDASH=
OPTIONS_STUCKLONG=t
OPTIONS_SPEC="\
git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
git rebase --continue | --abort | --skip | --edit-todo
--
Available options are
v,verbose! display a diffstat of what changed upstream
q,quiet! be quiet. implies --no-stat
autostash automatically stash/stash pop before and after
fork-point use 'merge-base --fork-point' to refine upstream
onto=! rebase onto given branch instead of upstream
r,rebase-merges? try to rebase merges instead of skipping them
p,preserve-merges! try to recreate merges instead of ignoring them
s,strategy=! use the given merge strategy
X,strategy-option=! pass the argument through to the merge strategy
no-ff! cherry-pick all commits, even if unchanged
f,force-rebase! cherry-pick all commits, even if unchanged
m,merge! use merging strategies to rebase
i,interactive! let the user edit the list of commits to rebase
x,exec=! add exec lines after each commit of the editable list
k,keep-empty preserve empty commits during rebase
allow-empty-message allow rebasing commits with empty messages
stat! display a diffstat of what changed upstream
n,no-stat! do not show diffstat of what changed upstream
verify allow pre-rebase hook to run
rerere-autoupdate allow rerere to update index with resolved conflicts
root! rebase all reachable commits up to the root(s)
autosquash move commits that begin with squash!/fixup! under -i
signoff add a Signed-off-by: line to each commit
committer-date-is-author-date! passed to 'git am'
ignore-date! passed to 'git am'
whitespace=! passed to 'git apply'
ignore-whitespace! passed to 'git apply'
C=! passed to 'git apply'
S,gpg-sign? GPG-sign commits
Actions:
continue! continue
abort! abort and check out the original branch
skip! skip current patch and continue
edit-todo! edit the todo list during an interactive rebase
quit! abort but keep HEAD where it is
show-current-patch! show the patch file being applied or merged
reschedule-failed-exec automatically reschedule failed exec commands
"
. git-sh-setup
set_reflog_action rebase
require_work_tree_exists
cd_to_toplevel
LF='
'
ok_to_skip_pre_rebase=
squash_onto=
unset onto
unset restrict_revision
cmd=
strategy=
strategy_opts=
do_merge=
merge_dir="$GIT_DIR"/rebase-merge
apply_dir="$GIT_DIR"/rebase-apply
verbose=
diffstat=
test "$(git config --bool rebase.stat)" = true && diffstat=t
autostash="$(git config --bool rebase.autostash || echo false)"
fork_point=auto
git_am_opt=
git_format_patch_opt=
rebase_root=
force_rebase=
allow_rerere_autoupdate=
# Non-empty if a rebase was in progress when 'git rebase' was invoked
in_progress=
# One of {am, merge, interactive}
type=
# One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge}
state_dir=
# One of {'', continue, skip, abort}, as parsed from command line
action=
rebase_merges=
rebase_cousins=
preserve_merges=
autosquash=
keep_empty=
allow_empty_message=--allow-empty-message
signoff=
reschedule_failed_exec=
test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
case "$(git config --bool commit.gpgsign)" in
true) gpg_sign_opt=-S ;;
*) gpg_sign_opt= ;;
esac
test "$(git config --bool rebase.reschedulefailedexec)" = "true" &&
reschedule_failed_exec=--reschedule-failed-exec
. git-rebase--common
read_basic_state () {
test -f "$state_dir/head-name" &&
test -f "$state_dir/onto" &&
head_name=$(cat "$state_dir"/head-name) &&
onto=$(cat "$state_dir"/onto) &&
# We always write to orig-head, but interactive rebase used to write to
# head. Fall back to reading from head to cover for the case that the
# user upgraded git with an ongoing interactive rebase.
if test -f "$state_dir"/orig-head
then
orig_head=$(cat "$state_dir"/orig-head)
else
orig_head=$(cat "$state_dir"/head)
fi &&
test -f "$state_dir"/quiet && GIT_QUIET=t
test -f "$state_dir"/verbose && verbose=t
test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)"
test -f "$state_dir"/strategy_opts &&
strategy_opts="$(cat "$state_dir"/strategy_opts)"
test -f "$state_dir"/allow_rerere_autoupdate &&
allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)"
test -f "$state_dir"/gpg_sign_opt &&
gpg_sign_opt="$(cat "$state_dir"/gpg_sign_opt)"
test -f "$state_dir"/signoff && {
signoff="$(cat "$state_dir"/signoff)"
force_rebase=t
}
test -f "$state_dir"/reschedule-failed-exec &&
reschedule_failed_exec=t
}
finish_rebase () {
rm -f "$(git rev-parse --git-path REBASE_HEAD)"
apply_autostash &&
{ git gc --auto || true; } &&
rm -rf "$state_dir"
}
run_specific_rebase () {
if [ "$interactive_rebase" = implied ]; then
GIT_SEQUENCE_EDITOR=:
export GIT_SEQUENCE_EDITOR
autosquash=
fi
if test -n "$interactive_rebase" -a -z "$preserve_merges"
then
. git-legacy-rebase--$type
git_rebase__$type
else
. git-rebase--$type
if test -z "$preserve_merges"
then
git_rebase__$type
else
git_rebase__preserve_merges
fi
fi
ret=$?
if test $ret -eq 0
then
finish_rebase
elif test $ret -eq 2 # special exit status for rebase -p
then
apply_autostash &&
rm -rf "$state_dir" &&
if test -n "$interactive_rebase" -a -z "$preserve_merges"
then
die "error: nothing to do"
else
die "Nothing to do"
fi
fi
exit $ret
}
run_pre_rebase_hook () {
if test -z "$ok_to_skip_pre_rebase" &&
test -x "$(git rev-parse --git-path hooks/pre-rebase)"
then
"$(git rev-parse --git-path hooks/pre-rebase)" ${1+"$@"} ||
die "$(gettext "The pre-rebase hook refused to rebase.")"
fi
}
test -f "$apply_dir"/applying &&
die "$(gettext "It looks like 'git am' is in progress. Cannot rebase.")"
if test -d "$apply_dir"
then
type=am
state_dir="$apply_dir"
elif test -d "$merge_dir"
then
type=interactive
if test -d "$merge_dir"/rewritten
then
type=preserve-merges
interactive_rebase=explicit
preserve_merges=t
elif test -f "$merge_dir"/interactive
then
interactive_rebase=explicit
fi
state_dir="$merge_dir"
fi
test -n "$type" && in_progress=t
total_argc=$#
while test $# != 0
do
case "$1" in
--no-verify)
ok_to_skip_pre_rebase=yes
;;
--verify)
ok_to_skip_pre_rebase=
;;
--continue|--skip|--abort|--quit|--edit-todo|--show-current-patch)
test $total_argc -eq 2 || usage
action=${1##--}
;;
--onto=*)
onto="${1#--onto=}"
;;
--exec=*)
cmd="${cmd}exec ${1#--exec=}${LF}"
test -z "$interactive_rebase" && interactive_rebase=implied
;;
--interactive)
interactive_rebase=explicit
;;
--keep-empty)
keep_empty=yes
;;
--allow-empty-message)
allow_empty_message=--allow-empty-message
;;
--no-keep-empty)
keep_empty=
;;
--rebase-merges)
rebase_merges=t
test -z "$interactive_rebase" && interactive_rebase=implied
;;
--rebase-merges=*)
rebase_merges=t
case "${1#*=}" in
rebase-cousins) rebase_cousins=t;;
no-rebase-cousins) rebase_cousins=;;
*) die "Unknown mode: $1";;
esac
test -z "$interactive_rebase" && interactive_rebase=implied
;;
--preserve-merges)
preserve_merges=t
test -z "$interactive_rebase" && interactive_rebase=implied
;;
--autosquash)
autosquash=t
;;
--no-autosquash)
autosquash=
;;
--fork-point)
fork_point=t
;;
--no-fork-point)
fork_point=
;;
--merge)
do_merge=t
;;
--strategy-option=*)
strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--${1#--strategy-option=}" | sed -e s/^.//)"
do_merge=t
test -z "$strategy" && strategy=recursive
;;
--strategy=*)
strategy="${1#--strategy=}"
do_merge=t
;;
--no-stat)
diffstat=
;;
--stat)
diffstat=t
;;
--autostash)
autostash=true
;;
--no-autostash)
autostash=false
;;
--verbose)
verbose=t
diffstat=t
GIT_QUIET=
;;
--quiet)
GIT_QUIET=t
git_am_opt="$git_am_opt -q"
verbose=
diffstat=
;;
--whitespace=*)
git_am_opt="$git_am_opt --whitespace=${1#--whitespace=}"
case "${1#--whitespace=}" in
fix|strip)
force_rebase=t
;;
warn|nowarn|error|error-all)
;; # okay, known whitespace option
*)
die "fatal: Invalid whitespace option: '${1#*=}'"
;;
esac
;;
--ignore-whitespace)
git_am_opt="$git_am_opt $1"
;;
--signoff)
signoff=--signoff
;;
--no-signoff)
signoff=
;;
--committer-date-is-author-date|--ignore-date)
git_am_opt="$git_am_opt $1"
force_rebase=t
;;
-C*[!0-9]*)
die "fatal: switch \`C' expects a numerical value"
;;
-C*)
git_am_opt="$git_am_opt $1"
;;
--root)
rebase_root=t
;;
--force-rebase|--no-ff)
force_rebase=t
;;
--rerere-autoupdate|--no-rerere-autoupdate)
allow_rerere_autoupdate="$1"
;;
--gpg-sign)
gpg_sign_opt=-S
;;
--gpg-sign=*)
gpg_sign_opt="-S${1#--gpg-sign=}"
;;
--reschedule-failed-exec)
reschedule_failed_exec=--reschedule-failed-exec
;;
--no-reschedule-failed-exec)
reschedule_failed_exec=
;;
--)
shift
break
;;
*)
usage
;;
esac
shift
done
test $# -gt 2 && usage
if test -n "$action"
then
test -z "$in_progress" && die "$(gettext "No rebase in progress?")"
# Only interactive rebase uses detailed reflog messages
if test -n "$interactive_rebase" && test "$GIT_REFLOG_ACTION" = rebase
then
GIT_REFLOG_ACTION="rebase -i ($action)"
export GIT_REFLOG_ACTION
fi
fi
if test "$action" = "edit-todo" && test -z "$interactive_rebase"
then
die "$(gettext "The --edit-todo action can only be used during interactive rebase.")"
fi
case "$action" in
continue)
# Sanity check
git rev-parse --verify HEAD >/dev/null ||
die "$(gettext "Cannot read HEAD")"
git update-index --ignore-submodules --refresh &&
git diff-files --quiet --ignore-submodules || {
echo "$(gettext "You must edit all merge conflicts and then
mark them as resolved using git add")"
exit 1
}
read_basic_state
run_specific_rebase
;;
skip)
output git reset --hard HEAD || exit $?
read_basic_state
run_specific_rebase
;;
abort)
git rerere clear
read_basic_state
case "$head_name" in
refs/*)
git symbolic-ref -m "rebase: aborting" HEAD $head_name ||
die "$(eval_gettext "Could not move back to \$head_name")"
;;
esac
output git reset --hard $orig_head
finish_rebase
exit
;;
quit)
exec rm -rf "$state_dir"
;;
edit-todo)
run_specific_rebase
;;
show-current-patch)
run_specific_rebase
die "BUG: run_specific_rebase is not supposed to return here"
;;
esac
# Make sure no rebase is in progress
if test -n "$in_progress"
then
state_dir_base=${state_dir##*/}
cmd_live_rebase="git rebase (--continue | --abort | --skip)"
cmd_clear_stale_rebase="rm -fr \"$state_dir\""
die "
$(eval_gettext 'It seems that there is already a $state_dir_base directory, and
I wonder if you are in the middle of another rebase. If that is the
case, please try
$cmd_live_rebase
If that is not the case, please
$cmd_clear_stale_rebase
and run me again. I am stopping in case you still have something
valuable there.')"
fi
if test -n "$rebase_root" && test -z "$onto"
then
test -z "$interactive_rebase" && interactive_rebase=implied
fi
if test -n "$keep_empty"
then
test -z "$interactive_rebase" && interactive_rebase=implied
fi
actually_interactive=
if test -n "$interactive_rebase"
then
if test -z "$preserve_merges"
then
type=interactive
else
type=preserve-merges
fi
actually_interactive=t
state_dir="$merge_dir"
elif test -n "$do_merge"
then
interactive_rebase=implied
type=interactive
state_dir="$merge_dir"
else
type=am
state_dir="$apply_dir"
fi
if test -t 2 && test -z "$GIT_QUIET"
then
git_format_patch_opt="$git_format_patch_opt --progress"
fi
incompatible_opts=$(echo " $git_am_opt " | \
sed -e 's/ -q / /g' -e 's/^ \(.*\) $/\1/')
if test -n "$incompatible_opts"
then
if test -n "$actually_interactive" || test "$do_merge"
then
die "$(gettext "fatal: cannot combine am options with either interactive or merge options")"
fi
fi
if test -n "$signoff"
then
test -n "$preserve_merges" &&
die "$(gettext "fatal: cannot combine '--signoff' with '--preserve-merges'")"
git_am_opt="$git_am_opt $signoff"
force_rebase=t
fi
if test -n "$preserve_merges"
then
# Note: incompatibility with --signoff handled in signoff block above
# Note: incompatibility with --interactive is just a strong warning;
# git-rebase.txt caveats with "unless you know what you are doing"
test -n "$rebase_merges" &&
die "$(gettext "fatal: cannot combine '--preserve-merges' with '--rebase-merges'")"
test -n "$reschedule_failed_exec" &&
die "$(gettext "error: cannot combine '--preserve-merges' with '--reschedule-failed-exec'")"
fi
if test -n "$rebase_merges"
then
test -n "$strategy_opts" &&
die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy-option'")"
test -n "$strategy" &&
die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy'")"
fi
if test -z "$rebase_root"
then
case "$#" in
0)
if ! upstream_name=$(git rev-parse --symbolic-full-name \
--verify -q @{upstream} 2>/dev/null)
then
. git-parse-remote
error_on_missing_default_upstream "rebase" "rebase" \
"against" "git rebase $(gettext '<branch>')"
fi
test "$fork_point" = auto && fork_point=t
;;
*) upstream_name="$1"
if test "$upstream_name" = "-"
then
upstream_name="@{-1}"
fi
shift
;;
esac
upstream=$(peel_committish "${upstream_name}") ||
die "$(eval_gettext "invalid upstream '\$upstream_name'")"
upstream_arg="$upstream_name"
else
if test -z "$onto"
then
empty_tree=$(git hash-object -t tree /dev/null)
onto=$(git commit-tree $empty_tree </dev/null)
squash_onto="$onto"
fi
unset upstream_name
unset upstream
test $# -gt 1 && usage
upstream_arg=--root
fi
# Make sure the branch to rebase onto is valid.
onto_name=${onto-"$upstream_name"}
case "$onto_name" in
*...*)
if left=${onto_name%...*} right=${onto_name#*...} &&
onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD})
then
case "$onto" in
?*"$LF"?*)
die "$(eval_gettext "\$onto_name: there are more than one merge bases")"
;;
'')
die "$(eval_gettext "\$onto_name: there is no merge base")"
;;
esac
else
die "$(eval_gettext "\$onto_name: there is no merge base")"
fi
;;
*)
onto=$(peel_committish "$onto_name") ||
die "$(eval_gettext "Does not point to a valid commit: \$onto_name")"
;;
esac
# If the branch to rebase is given, that is the branch we will rebase
# $branch_name -- branch/commit being rebased, or HEAD (already detached)
# $orig_head -- commit object name of tip of the branch before rebasing
# $head_name -- refs/heads/<that-branch> or "detached HEAD"
switch_to=
case "$#" in
1)
# Is it "rebase other $branchname" or "rebase other $commit"?
branch_name="$1"
switch_to="$1"
# Is it a local branch?
if git show-ref --verify --quiet -- "refs/heads/$branch_name" &&
orig_head=$(git rev-parse -q --verify "refs/heads/$branch_name")
then
head_name="refs/heads/$branch_name"
# If not is it a valid ref (branch or commit)?
elif orig_head=$(git rev-parse -q --verify "$branch_name")
then
head_name="detached HEAD"
else
die "$(eval_gettext "fatal: no such branch/commit '\$branch_name'")"
fi
;;
0)
# Do not need to switch branches, we are already on it.
if branch_name=$(git symbolic-ref -q HEAD)
then
head_name=$branch_name
branch_name=$(expr "z$branch_name" : 'zrefs/heads/\(.*\)')
else
head_name="detached HEAD"
branch_name=HEAD
fi
orig_head=$(git rev-parse --verify HEAD) || exit
;;
*)
die "BUG: unexpected number of arguments left to parse"
;;
esac
if test "$fork_point" = t
then
new_upstream=$(git merge-base --fork-point "$upstream_name" \
"${switch_to:-HEAD}")
if test -n "$new_upstream"
then
restrict_revision=$new_upstream
fi
fi
if test "$autostash" = true && ! (require_clean_work_tree) 2>/dev/null
then
stash_sha1=$(git stash create "autostash") ||
die "$(gettext 'Cannot autostash')"
mkdir -p "$state_dir" &&
echo $stash_sha1 >"$state_dir/autostash" &&
stash_abbrev=$(git rev-parse --short $stash_sha1) &&
echo "$(eval_gettext 'Created autostash: $stash_abbrev')" &&
git reset --hard
fi
require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")"
# Now we are rebasing commits $upstream..$orig_head (or with --root,
# everything leading up to $orig_head) on top of $onto
# Check if we are already based on $onto with linear history,
# but this should be done only when upstream and onto are the same
# and if this is not an interactive rebase.
mb=$(git merge-base "$onto" "$orig_head")
if test -z "$actually_interactive" && test "$upstream" = "$onto" &&
test "$mb" = "$onto" && test -z "$restrict_revision" &&
# linear history?
! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > /dev/null
then
if test -z "$force_rebase"
then
# Lazily switch to the target branch if needed...
test -z "$switch_to" ||
GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" \
git checkout -q "$switch_to" --
if test "$branch_name" = "HEAD" &&
! git symbolic-ref -q HEAD
then
say "$(eval_gettext "HEAD is up to date.")"
else
say "$(eval_gettext "Current branch \$branch_name is up to date.")"
fi
finish_rebase
exit 0
else
if test "$branch_name" = "HEAD" &&
! git symbolic-ref -q HEAD
then
say "$(eval_gettext "HEAD is up to date, rebase forced.")"
else
say "$(eval_gettext "Current branch \$branch_name is up to date, rebase forced.")"
fi
fi
fi
# If a hook exists, give it a chance to interrupt
run_pre_rebase_hook "$upstream_arg" "$@"
if test -n "$diffstat"
then
if test -n "$verbose"
then
if test -z "$mb"
then
echo "$(eval_gettext "Changes to \$onto:")"
else
echo "$(eval_gettext "Changes from \$mb to \$onto:")"
fi
fi
mb_tree="${mb:-$(git hash-object -t tree /dev/null)}"
# We want color (if set), but no pager
GIT_PAGER='' git diff --stat --summary "$mb_tree" "$onto"
fi
if test -z "$actually_interactive" && test "$mb" = "$orig_head"
then
say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")"
GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
git checkout -q "$onto^0" || die "could not detach HEAD"
# If the $onto is a proper descendant of the tip of the branch, then
# we just fast-forwarded.
git update-ref ORIG_HEAD $orig_head
move_to_original_branch
finish_rebase
exit 0
fi
test -n "$interactive_rebase" && run_specific_rebase
# Detach HEAD and reset the tree
say "$(gettext "First, rewinding head to replay your work on top of it...")"
GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
git checkout -q "$onto^0" || die "could not detach HEAD"
git update-ref ORIG_HEAD $orig_head
if test -n "$rebase_root"
then
revisions="$onto..$orig_head"
else
revisions="${restrict_revision-$upstream}..$orig_head"
fi
run_specific_rebase

View File

@ -0,0 +1,283 @@
# This shell script fragment is sourced by git-rebase to implement
# its interactive mode. "git rebase --interactive" makes it easy
# to fix up commits in the middle of a series and rearrange commits.
#
# Copyright (c) 2006 Johannes E. Schindelin
#
# The original idea comes from Eric W. Biederman, in
# https://public-inbox.org/git/m1odwkyuf5.fsf_-_@ebiederm.dsl.xmission.com/
#
# The file containing rebase commands, comments, and empty lines.
# This file is created by "git rebase -i" then edited by the user. As
# the lines are processed, they are removed from the front of this
# file and written to the tail of $done.
todo="$state_dir"/git-rebase-todo
GIT_CHERRY_PICK_HELP="$resolvemsg"
export GIT_CHERRY_PICK_HELP
comment_char=$(git config --get core.commentchar 2>/dev/null)
case "$comment_char" in
'' | auto)
comment_char="#"
;;
?)
;;
*)
comment_char=$(echo "$comment_char" | cut -c1)
;;
esac
orig_reflog_action="$GIT_REFLOG_ACTION"
comment_for_reflog () {
case "$orig_reflog_action" in
''|rebase*)
GIT_REFLOG_ACTION="rebase -i ($1)"
export GIT_REFLOG_ACTION
;;
esac
}
append_todo_help () {
gettext "
Commands:
p, pick <commit> = use commit
r, reword <commit> = use commit, but edit the commit message
e, edit <commit> = use commit, but stop for amending
s, squash <commit> = use commit, but meld into previous commit
f, fixup <commit> = like \"squash\", but discard this commit's log message
x, exec <command> = run command (the rest of the line) using shell
d, drop <commit> = remove commit
l, label <label> = label current HEAD with a name
t, reset <label> = reset HEAD to a label
m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
. create a merge commit using the original merge commit's
. message (or the oneline, if no original merge commit was
. specified). Use -c <commit> to reword the commit message.
These lines can be re-ordered; they are executed from top to bottom.
" | git stripspace --comment-lines >>"$todo"
if test $(get_missing_commit_check_level) = error
then
gettext "
Do not remove any line. Use 'drop' explicitly to remove a commit.
" | git stripspace --comment-lines >>"$todo"
else
gettext "
If you remove a line here THAT COMMIT WILL BE LOST.
" | git stripspace --comment-lines >>"$todo"
fi
}
die_abort () {
apply_autostash
rm -rf "$state_dir"
die "$1"
}
has_action () {
test -n "$(git stripspace --strip-comments <"$1")"
}
git_sequence_editor () {
if test -z "$GIT_SEQUENCE_EDITOR"
then
GIT_SEQUENCE_EDITOR="$(git config sequence.editor)"
if [ -z "$GIT_SEQUENCE_EDITOR" ]
then
GIT_SEQUENCE_EDITOR="$(git var GIT_EDITOR)" || return $?
fi
fi
eval "$GIT_SEQUENCE_EDITOR" '"$@"'
}
expand_todo_ids() {
git rebase--interactive --expand-ids
}
collapse_todo_ids() {
git rebase--interactive --shorten-ids
}
# Switch to the branch in $into and notify it in the reflog
checkout_onto () {
GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
output git checkout $onto || die_abort "$(gettext "could not detach HEAD")"
git update-ref ORIG_HEAD $orig_head
}
get_missing_commit_check_level () {
check_level=$(git config --get rebase.missingCommitsCheck)
check_level=${check_level:-ignore}
# Don't be case sensitive
printf '%s' "$check_level" | tr 'A-Z' 'a-z'
}
# Initiate an action. If the cannot be any
# further action it may exec a command
# or exit and not return.
#
# TODO: Consider a cleaner return model so it
# never exits and always return 0 if process
# is complete.
#
# Parameter 1 is the action to initiate.
#
# Returns 0 if the action was able to complete
# and if 1 if further processing is required.
initiate_action () {
case "$1" in
continue)
exec git rebase--interactive ${force_rebase:+--no-ff} $allow_empty_message \
--continue
;;
skip)
git rerere clear
exec git rebase--interactive ${force_rebase:+--no-ff} $allow_empty_message \
--continue
;;
edit-todo)
git stripspace --strip-comments <"$todo" >"$todo".new
mv -f "$todo".new "$todo"
collapse_todo_ids
append_todo_help
gettext "
You are editing the todo file of an ongoing interactive rebase.
To continue rebase after editing, run:
git rebase --continue
" | git stripspace --comment-lines >>"$todo"
git_sequence_editor "$todo" ||
die "$(gettext "Could not execute editor")"
expand_todo_ids
exit
;;
show-current-patch)
exec git show REBASE_HEAD --
;;
*)
return 1 # continue
;;
esac
}
setup_reflog_action () {
comment_for_reflog start
if test ! -z "$switch_to"
then
GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to"
output git checkout "$switch_to" -- ||
die "$(eval_gettext "Could not checkout \$switch_to")"
comment_for_reflog start
fi
}
init_basic_state () {
orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")"
mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")"
rm -f "$(git rev-parse --git-path REBASE_HEAD)"
: > "$state_dir"/interactive || die "$(gettext "Could not mark as interactive")"
write_basic_state
}
init_revisions_and_shortrevisions () {
shorthead=$(git rev-parse --short $orig_head)
shortonto=$(git rev-parse --short $onto)
if test -z "$rebase_root"
# this is now equivalent to ! -z "$upstream"
then
shortupstream=$(git rev-parse --short $upstream)
revisions=$upstream...$orig_head
shortrevisions=$shortupstream..$shorthead
else
revisions=$onto...$orig_head
shortrevisions=$shorthead
test -z "$squash_onto" ||
echo "$squash_onto" >"$state_dir"/squash-onto
fi
}
complete_action() {
test -s "$todo" || echo noop >> "$todo"
test -z "$autosquash" || git rebase--interactive --rearrange-squash || exit
test -n "$cmd" && git rebase--interactive --add-exec-commands --cmd "$cmd"
todocount=$(git stripspace --strip-comments <"$todo" | wc -l)
todocount=${todocount##* }
cat >>"$todo" <<EOF
$comment_char $(eval_ngettext \
"Rebase \$shortrevisions onto \$shortonto (\$todocount command)" \
"Rebase \$shortrevisions onto \$shortonto (\$todocount commands)" \
"$todocount")
EOF
append_todo_help
gettext "
However, if you remove everything, the rebase will be aborted.
" | git stripspace --comment-lines >>"$todo"
if test -z "$keep_empty"
then
printf '%s\n' "$comment_char $(gettext "Note that empty commits are commented out")" >>"$todo"
fi
has_action "$todo" ||
return 2
cp "$todo" "$todo".backup
collapse_todo_ids
git_sequence_editor "$todo" ||
die_abort "$(gettext "Could not execute editor")"
has_action "$todo" ||
return 2
git rebase--interactive --check-todo-list || {
ret=$?
checkout_onto
exit $ret
}
expand_todo_ids
test -n "$force_rebase" ||
onto="$(git rebase--interactive --skip-unnecessary-picks)" ||
die "Could not skip unnecessary pick commands"
checkout_onto
require_clean_work_tree "rebase"
exec git rebase--interactive ${force_rebase:+--no-ff} $allow_empty_message \
--continue
}
git_rebase__interactive () {
initiate_action "$action"
ret=$?
if test $ret = 0; then
return 0
fi
setup_reflog_action
init_basic_state
init_revisions_and_shortrevisions
git rebase--interactive --make-script ${keep_empty:+--keep-empty} \
${rebase_merges:+--rebase-merges} \
${rebase_cousins:+--rebase-cousins} \
$revisions ${restrict_revision+^$restrict_revision} >"$todo" ||
die "$(gettext "Could not generate todo list")"
complete_action
}

View File

@ -0,0 +1,797 @@
#!/bin/sh
# Copyright (c) 2007, Nanako Shiraishi
dashless=$(basename "$0" | sed -e 's/-/ /')
USAGE="list [<options>]
or: $dashless show [<stash>]
or: $dashless drop [-q|--quiet] [<stash>]
or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>]
or: $dashless branch <branchname> [<stash>]
or: $dashless save [--patch] [-k|--[no-]keep-index] [-q|--quiet]
[-u|--include-untracked] [-a|--all] [<message>]
or: $dashless [push [--patch] [-k|--[no-]keep-index] [-q|--quiet]
[-u|--include-untracked] [-a|--all] [-m <message>]
[-- <pathspec>...]]
or: $dashless clear"
SUBDIRECTORY_OK=Yes
OPTIONS_SPEC=
START_DIR=$(pwd)
. git-sh-setup
require_work_tree
prefix=$(git rev-parse --show-prefix) || exit 1
cd_to_toplevel
TMP="$GIT_DIR/.git-stash.$$"
TMPindex=${GIT_INDEX_FILE-"$(git rev-parse --git-path index)"}.stash.$$
trap 'rm -f "$TMP-"* "$TMPindex"' 0
ref_stash=refs/stash
if git config --get-colorbool color.interactive; then
help_color="$(git config --get-color color.interactive.help 'red bold')"
reset_color="$(git config --get-color '' reset)"
else
help_color=
reset_color=
fi
no_changes () {
git diff-index --quiet --cached HEAD --ignore-submodules -- "$@" &&
git diff-files --quiet --ignore-submodules -- "$@" &&
(test -z "$untracked" || test -z "$(untracked_files "$@")")
}
untracked_files () {
if test "$1" = "-z"
then
shift
z=-z
else
z=
fi
excl_opt=--exclude-standard
test "$untracked" = "all" && excl_opt=
git ls-files -o $z $excl_opt -- "$@"
}
prepare_fallback_ident () {
if ! git -c user.useconfigonly=yes var GIT_COMMITTER_IDENT >/dev/null 2>&1
then
GIT_AUTHOR_NAME="git stash"
GIT_AUTHOR_EMAIL=git@stash
GIT_COMMITTER_NAME="git stash"
GIT_COMMITTER_EMAIL=git@stash
export GIT_AUTHOR_NAME
export GIT_AUTHOR_EMAIL
export GIT_COMMITTER_NAME
export GIT_COMMITTER_EMAIL
fi
}
clear_stash () {
if test $# != 0
then
die "$(gettext "git stash clear with parameters is unimplemented")"
fi
if current=$(git rev-parse --verify --quiet $ref_stash)
then
git update-ref -d $ref_stash $current
fi
}
maybe_quiet () {
case "$1" in
--keep-stdout)
shift
if test -n "$GIT_QUIET"
then
eval "$@" 2>/dev/null
else
eval "$@"
fi
;;
*)
if test -n "$GIT_QUIET"
then
eval "$@" >/dev/null 2>&1
else
eval "$@"
fi
;;
esac
}
create_stash () {
prepare_fallback_ident
stash_msg=
untracked=
while test $# != 0
do
case "$1" in
-m|--message)
shift
stash_msg=${1?"BUG: create_stash () -m requires an argument"}
;;
-m*)
stash_msg=${1#-m}
;;
--message=*)
stash_msg=${1#--message=}
;;
-u|--include-untracked)
shift
untracked=${1?"BUG: create_stash () -u requires an argument"}
;;
--)
shift
break
;;
esac
shift
done
git update-index -q --refresh
if maybe_quiet no_changes "$@"
then
exit 0
fi
# state of the base commit
if b_commit=$(maybe_quiet --keep-stdout git rev-parse --verify HEAD)
then
head=$(git rev-list --oneline -n 1 HEAD --)
elif test -n "$GIT_QUIET"
then
exit 1
else
die "$(gettext "You do not have the initial commit yet")"
fi
if branch=$(git symbolic-ref -q HEAD)
then
branch=${branch#refs/heads/}
else
branch='(no branch)'
fi
msg=$(printf '%s: %s' "$branch" "$head")
# state of the index
i_tree=$(git write-tree) &&
i_commit=$(printf 'index on %s\n' "$msg" |
git commit-tree $i_tree -p $b_commit) ||
die "$(gettext "Cannot save the current index state")"
if test -n "$untracked"
then
# Untracked files are stored by themselves in a parentless commit, for
# ease of unpacking later.
u_commit=$(
untracked_files -z "$@" | (
GIT_INDEX_FILE="$TMPindex" &&
export GIT_INDEX_FILE &&
rm -f "$TMPindex" &&
git update-index -z --add --remove --stdin &&
u_tree=$(git write-tree) &&
printf 'untracked files on %s\n' "$msg" | git commit-tree $u_tree &&
rm -f "$TMPindex"
) ) || die "$(gettext "Cannot save the untracked files")"
untracked_commit_option="-p $u_commit";
else
untracked_commit_option=
fi
if test -z "$patch_mode"
then
# state of the working tree
w_tree=$( (
git read-tree --index-output="$TMPindex" -m $i_tree &&
GIT_INDEX_FILE="$TMPindex" &&
export GIT_INDEX_FILE &&
git diff-index --name-only -z HEAD -- "$@" >"$TMP-stagenames" &&
git update-index -z --add --remove --stdin <"$TMP-stagenames" &&
git write-tree &&
rm -f "$TMPindex"
) ) ||
die "$(gettext "Cannot save the current worktree state")"
else
rm -f "$TMP-index" &&
GIT_INDEX_FILE="$TMP-index" git read-tree HEAD &&
# find out what the user wants
GIT_INDEX_FILE="$TMP-index" \
git add--interactive --patch=stash -- "$@" &&
# state of the working tree
w_tree=$(GIT_INDEX_FILE="$TMP-index" git write-tree) ||
die "$(gettext "Cannot save the current worktree state")"
git diff-tree -p HEAD $w_tree -- >"$TMP-patch" &&
test -s "$TMP-patch" ||
die "$(gettext "No changes selected")"
rm -f "$TMP-index" ||
die "$(gettext "Cannot remove temporary index (can't happen)")"
fi
# create the stash
if test -z "$stash_msg"
then
stash_msg=$(printf 'WIP on %s' "$msg")
else
stash_msg=$(printf 'On %s: %s' "$branch" "$stash_msg")
fi
w_commit=$(printf '%s\n' "$stash_msg" |
git commit-tree $w_tree -p $b_commit -p $i_commit $untracked_commit_option) ||
die "$(gettext "Cannot record working tree state")"
}
store_stash () {
while test $# != 0
do
case "$1" in
-m|--message)
shift
stash_msg="$1"
;;
-m*)
stash_msg=${1#-m}
;;
--message=*)
stash_msg=${1#--message=}
;;
-q|--quiet)
quiet=t
;;
*)
break
;;
esac
shift
done
test $# = 1 ||
die "$(eval_gettext "\"$dashless store\" requires one <commit> argument")"
w_commit="$1"
if test -z "$stash_msg"
then
stash_msg="Created via \"git stash store\"."
fi
git update-ref --create-reflog -m "$stash_msg" $ref_stash $w_commit
ret=$?
test $ret != 0 && test -z "$quiet" &&
die "$(eval_gettext "Cannot update \$ref_stash with \$w_commit")"
return $ret
}
push_stash () {
keep_index=
patch_mode=
untracked=
stash_msg=
while test $# != 0
do
case "$1" in
-k|--keep-index)
keep_index=t
;;
--no-keep-index)
keep_index=n
;;
-p|--patch)
patch_mode=t
# only default to keep if we don't already have an override
test -z "$keep_index" && keep_index=t
;;
-q|--quiet)
GIT_QUIET=t
;;
-u|--include-untracked)
untracked=untracked
;;
-a|--all)
untracked=all
;;
-m|--message)
shift
test -z ${1+x} && usage
stash_msg=$1
;;
-m*)
stash_msg=${1#-m}
;;
--message=*)
stash_msg=${1#--message=}
;;
--help)
show_help
;;
--)
shift
break
;;
-*)
option="$1"
eval_gettextln "error: unknown option for 'stash push': \$option"
usage
;;
*)
break
;;
esac
shift
done
eval "set $(git rev-parse --sq --prefix "$prefix" -- "$@")"
if test -n "$patch_mode" && test -n "$untracked"
then
die "$(gettext "Can't use --patch and --include-untracked or --all at the same time")"
fi
test -n "$untracked" || git ls-files --error-unmatch -- "$@" >/dev/null || exit 1
git update-index -q --refresh
if maybe_quiet no_changes "$@"
then
say "$(gettext "No local changes to save")"
exit 0
fi
git reflog exists $ref_stash ||
clear_stash || die "$(gettext "Cannot initialize stash")"
create_stash -m "$stash_msg" -u "$untracked" -- "$@"
store_stash -m "$stash_msg" -q $w_commit ||
die "$(gettext "Cannot save the current status")"
say "$(eval_gettext "Saved working directory and index state \$stash_msg")"
if test -z "$patch_mode"
then
test "$untracked" = "all" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=
if test -n "$untracked" && test $# = 0
then
git clean --force --quiet -d $CLEAN_X_OPTION
fi
if test $# != 0
then
test -z "$untracked" && UPDATE_OPTION="-u" || UPDATE_OPTION=
test "$untracked" = "all" && FORCE_OPTION="--force" || FORCE_OPTION=
git add $UPDATE_OPTION $FORCE_OPTION -- "$@"
git diff-index -p --cached --binary HEAD -- "$@" |
git apply --index -R
else
git reset --hard -q
fi
if test "$keep_index" = "t" && test -n "$i_tree"
then
git read-tree --reset $i_tree
git ls-files -z --modified -- "$@" |
git checkout-index -z --force --stdin
fi
else
git apply -R < "$TMP-patch" ||
die "$(gettext "Cannot remove worktree changes")"
if test "$keep_index" != "t"
then
git reset -q -- "$@"
fi
fi
}
save_stash () {
push_options=
while test $# != 0
do
case "$1" in
-q|--quiet)
GIT_QUIET=t
;;
--)
shift
break
;;
-*)
# pass all options through to push_stash
push_options="$push_options $1"
;;
*)
break
;;
esac
shift
done
stash_msg="$*"
if test -z "$stash_msg"
then
push_stash $push_options
else
push_stash $push_options -m "$stash_msg"
fi
}
have_stash () {
git rev-parse --verify --quiet $ref_stash >/dev/null
}
list_stash () {
have_stash || return 0
git log --format="%gd: %gs" -g --first-parent -m "$@" $ref_stash --
}
show_stash () {
ALLOW_UNKNOWN_FLAGS=t
assert_stash_like "$@"
if test -z "$FLAGS"
then
if test "$(git config --bool stash.showStat || echo true)" = "true"
then
FLAGS=--stat
fi
if test "$(git config --bool stash.showPatch || echo false)" = "true"
then
FLAGS=${FLAGS}${FLAGS:+ }-p
fi
if test -z "$FLAGS"
then
return 0
fi
fi
git diff ${FLAGS} $b_commit $w_commit
}
show_help () {
exec git help stash
exit 1
}
#
# Parses the remaining options looking for flags and
# at most one revision defaulting to ${ref_stash}@{0}
# if none found.
#
# Derives related tree and commit objects from the
# revision, if one is found.
#
# stash records the work tree, and is a merge between the
# base commit (first parent) and the index tree (second parent).
#
# REV is set to the symbolic version of the specified stash-like commit
# IS_STASH_LIKE is non-blank if ${REV} looks like a stash
# IS_STASH_REF is non-blank if the ${REV} looks like a stash ref
# s is set to the SHA1 of the stash commit
# w_commit is set to the commit containing the working tree
# b_commit is set to the base commit
# i_commit is set to the commit containing the index tree
# u_commit is set to the commit containing the untracked files tree
# w_tree is set to the working tree
# b_tree is set to the base tree
# i_tree is set to the index tree
# u_tree is set to the untracked files tree
#
# GIT_QUIET is set to t if -q is specified
# INDEX_OPTION is set to --index if --index is specified.
# FLAGS is set to the remaining flags (if allowed)
#
# dies if:
# * too many revisions specified
# * no revision is specified and there is no stash stack
# * a revision is specified which cannot be resolve to a SHA1
# * a non-existent stash reference is specified
# * unknown flags were set and ALLOW_UNKNOWN_FLAGS is not "t"
#
parse_flags_and_rev()
{
test "$PARSE_CACHE" = "$*" && return 0 # optimisation
PARSE_CACHE="$*"
IS_STASH_LIKE=
IS_STASH_REF=
INDEX_OPTION=
s=
w_commit=
b_commit=
i_commit=
u_commit=
w_tree=
b_tree=
i_tree=
u_tree=
FLAGS=
REV=
for opt
do
case "$opt" in
-q|--quiet)
GIT_QUIET=-t
;;
--index)
INDEX_OPTION=--index
;;
--help)
show_help
;;
-*)
test "$ALLOW_UNKNOWN_FLAGS" = t ||
die "$(eval_gettext "unknown option: \$opt")"
FLAGS="${FLAGS}${FLAGS:+ }$opt"
;;
*)
REV="${REV}${REV:+ }'$opt'"
;;
esac
done
eval set -- $REV
case $# in
0)
have_stash || die "$(gettext "No stash entries found.")"
set -- ${ref_stash}@{0}
;;
1)
:
;;
*)
die "$(eval_gettext "Too many revisions specified: \$REV")"
;;
esac
case "$1" in
*[!0-9]*)
:
;;
*)
set -- "${ref_stash}@{$1}"
;;
esac
REV=$(git rev-parse --symbolic --verify --quiet "$1") || {
reference="$1"
die "$(eval_gettext "\$reference is not a valid reference")"
}
i_commit=$(git rev-parse --verify --quiet "$REV^2") &&
set -- $(git rev-parse "$REV" "$REV^1" "$REV:" "$REV^1:" "$REV^2:" 2>/dev/null) &&
s=$1 &&
w_commit=$1 &&
b_commit=$2 &&
w_tree=$3 &&
b_tree=$4 &&
i_tree=$5 &&
IS_STASH_LIKE=t &&
test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" &&
IS_STASH_REF=t
u_commit=$(git rev-parse --verify --quiet "$REV^3") &&
u_tree=$(git rev-parse "$REV^3:" 2>/dev/null)
}
is_stash_like()
{
parse_flags_and_rev "$@"
test -n "$IS_STASH_LIKE"
}
assert_stash_like() {
is_stash_like "$@" || {
args="$*"
die "$(eval_gettext "'\$args' is not a stash-like commit")"
}
}
is_stash_ref() {
is_stash_like "$@" && test -n "$IS_STASH_REF"
}
assert_stash_ref() {
is_stash_ref "$@" || {
args="$*"
die "$(eval_gettext "'\$args' is not a stash reference")"
}
}
apply_stash () {
assert_stash_like "$@"
git update-index -q --refresh || die "$(gettext "unable to refresh index")"
# current index state
c_tree=$(git write-tree) ||
die "$(gettext "Cannot apply a stash in the middle of a merge")"
unstashed_index_tree=
if test -n "$INDEX_OPTION" && test "$b_tree" != "$i_tree" &&
test "$c_tree" != "$i_tree"
then
git diff-tree --binary $s^2^..$s^2 | git apply --cached
test $? -ne 0 &&
die "$(gettext "Conflicts in index. Try without --index.")"
unstashed_index_tree=$(git write-tree) ||
die "$(gettext "Could not save index tree")"
git reset
fi
if test -n "$u_tree"
then
GIT_INDEX_FILE="$TMPindex" git read-tree "$u_tree" &&
GIT_INDEX_FILE="$TMPindex" git checkout-index --all &&
rm -f "$TMPindex" ||
die "$(gettext "Could not restore untracked files from stash entry")"
fi
eval "
GITHEAD_$w_tree='Stashed changes' &&
GITHEAD_$c_tree='Updated upstream' &&
GITHEAD_$b_tree='Version stash was based on' &&
export GITHEAD_$w_tree GITHEAD_$c_tree GITHEAD_$b_tree
"
if test -n "$GIT_QUIET"
then
GIT_MERGE_VERBOSITY=0 && export GIT_MERGE_VERBOSITY
fi
if git merge-recursive $b_tree -- $c_tree $w_tree
then
# No conflict
if test -n "$unstashed_index_tree"
then
git read-tree "$unstashed_index_tree"
else
a="$TMP-added" &&
git diff-index --cached --name-only --diff-filter=A $c_tree >"$a" &&
git read-tree --reset $c_tree &&
git update-index --add --stdin <"$a" ||
die "$(gettext "Cannot unstage modified files")"
rm -f "$a"
fi
squelch=
if test -n "$GIT_QUIET"
then
squelch='>/dev/null 2>&1'
fi
(cd "$START_DIR" && eval "git status $squelch") || :
else
# Merge conflict; keep the exit status from merge-recursive
status=$?
git rerere
if test -n "$INDEX_OPTION"
then
gettextln "Index was not unstashed." >&2
fi
exit $status
fi
}
pop_stash() {
assert_stash_ref "$@"
if apply_stash "$@"
then
drop_stash "$@"
else
status=$?
say "$(gettext "The stash entry is kept in case you need it again.")"
exit $status
fi
}
drop_stash () {
assert_stash_ref "$@"
git reflog delete --updateref --rewrite "${REV}" &&
say "$(eval_gettext "Dropped \${REV} (\$s)")" ||
die "$(eval_gettext "\${REV}: Could not drop stash entry")"
# clear_stash if we just dropped the last stash entry
git rev-parse --verify --quiet "$ref_stash@{0}" >/dev/null ||
clear_stash
}
apply_to_branch () {
test -n "$1" || die "$(gettext "No branch name specified")"
branch=$1
shift 1
set -- --index "$@"
assert_stash_like "$@"
git checkout -b $branch $REV^ &&
apply_stash "$@" && {
test -z "$IS_STASH_REF" || drop_stash "$@"
}
}
test "$1" = "-p" && set "push" "$@"
PARSE_CACHE='--not-parsed'
# The default command is "push" if nothing but options are given
seen_non_option=
for opt
do
case "$opt" in
--) break ;;
-*) ;;
*) seen_non_option=t; break ;;
esac
done
test -n "$seen_non_option" || set "push" "$@"
# Main command set
case "$1" in
list)
shift
list_stash "$@"
;;
show)
shift
show_stash "$@"
;;
save)
shift
save_stash "$@"
;;
push)
shift
push_stash "$@"
;;
apply)
shift
apply_stash "$@"
;;
clear)
shift
clear_stash "$@"
;;
create)
shift
create_stash -m "$*" && echo "$w_commit"
;;
store)
shift
store_stash "$@"
;;
drop)
shift
drop_stash "$@"
;;
pop)
shift
pop_stash "$@"
;;
branch)
shift
apply_to_branch "$@"
;;
*)
case $# in
0)
push_stash &&
say "$(gettext "(To restore them type \"git stash apply\")")"
;;
*)
usage
esac
;;
esac

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,112 @@
#!/bin/sh
#
# Copyright (c) 2005 Junio C Hamano
#
# Resolve two or more trees.
#
. git-sh-setup
LF='
'
# The first parameters up to -- are merge bases; the rest are heads.
bases= head= remotes= sep_seen=
for arg
do
case ",$sep_seen,$head,$arg," in
*,--,)
sep_seen=yes
;;
,yes,,*)
head=$arg
;;
,yes,*)
remotes="$remotes$arg "
;;
*)
bases="$bases$arg "
;;
esac
done
# Reject if this is not an octopus -- resolve should be used instead.
case "$remotes" in
?*' '?*)
;;
*)
exit 2 ;;
esac
# MRC is the current "merge reference commit"
# MRT is the current "merge result tree"
if ! git diff-index --quiet --cached HEAD --
then
gettextln "Error: Your local changes to the following files would be overwritten by merge"
git diff-index --cached --name-only HEAD -- | sed -e 's/^/ /'
exit 2
fi
MRC=$(git rev-parse --verify -q $head)
MRT=$(git write-tree)
NON_FF_MERGE=0
OCTOPUS_FAILURE=0
for SHA1 in $remotes
do
case "$OCTOPUS_FAILURE" in
1)
# We allow only last one to have a hand-resolvable
# conflicts. Last round failed and we still had
# a head to merge.
gettextln "Automated merge did not work."
gettextln "Should not be doing an octopus."
exit 2
esac
eval pretty_name=\${GITHEAD_$SHA1:-$SHA1}
if test "$SHA1" = "$pretty_name"
then
SHA1_UP="$(echo "$SHA1" | tr a-z A-Z)"
eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name}
fi
common=$(git merge-base --all $SHA1 $MRC) ||
die "$(eval_gettext "Unable to find common commit with \$pretty_name")"
case "$LF$common$LF" in
*"$LF$SHA1$LF"*)
eval_gettextln "Already up to date with \$pretty_name"
continue
;;
esac
if test "$common,$NON_FF_MERGE" = "$MRC,0"
then
# The first head being merged was a fast-forward.
# Advance MRC to the head being merged, and use that
# tree as the intermediate result of the merge.
# We still need to count this as part of the parent set.
eval_gettextln "Fast-forwarding to: \$pretty_name"
git read-tree -u -m $head $SHA1 || exit
MRC=$SHA1 MRT=$(git write-tree)
continue
fi
NON_FF_MERGE=1
eval_gettextln "Trying simple merge with \$pretty_name"
git read-tree -u -m --aggressive $common $MRT $SHA1 || exit 2
next=$(git write-tree 2>/dev/null)
if test $? -ne 0
then
gettextln "Simple merge did not work, trying automatic merge."
git merge-index -o git-merge-one-file -a ||
OCTOPUS_FAILURE=1
next=$(git write-tree 2>/dev/null)
fi
MRC="$MRC $SHA1"
MRT=$next
done
exit "$OCTOPUS_FAILURE"

View File

@ -0,0 +1,167 @@
#!/bin/sh
#
# Copyright (c) Linus Torvalds, 2005
#
# This is the git per-file merge script, called with
#
# $1 - original file SHA1 (or empty)
# $2 - file in branch1 SHA1 (or empty)
# $3 - file in branch2 SHA1 (or empty)
# $4 - pathname in repository
# $5 - original file mode (or empty)
# $6 - file in branch1 mode (or empty)
# $7 - file in branch2 mode (or empty)
#
# Handle some trivial cases.. The _really_ trivial cases have
# been handled already by git read-tree, but that one doesn't
# do any merges that might change the tree layout.
USAGE='<orig blob> <our blob> <their blob> <path>'
USAGE="$USAGE <orig mode> <our mode> <their mode>"
LONG_USAGE="usage: git merge-one-file $USAGE
Blob ids and modes should be empty for missing files."
SUBDIRECTORY_OK=Yes
. git-sh-setup
cd_to_toplevel
require_work_tree
if test $# != 7
then
echo "$LONG_USAGE"
exit 1
fi
case "${1:-.}${2:-.}${3:-.}" in
#
# Deleted in both or deleted in one and unchanged in the other
#
"$1.." | "$1.$1" | "$1$1.")
if { test -z "$6" && test "$5" != "$7"; } ||
{ test -z "$7" && test "$5" != "$6"; }
then
echo "ERROR: File $4 deleted on one branch but had its" >&2
echo "ERROR: permissions changed on the other." >&2
exit 1
fi
if test -n "$2"
then
echo "Removing $4"
else
# read-tree checked that index matches HEAD already,
# so we know we do not have this path tracked.
# there may be an unrelated working tree file here,
# which we should just leave unmolested. Make sure
# we do not have it in the index, though.
exec git update-index --remove -- "$4"
fi
if test -f "$4"
then
rm -f -- "$4" &&
rmdir -p "$(expr "z$4" : 'z\(.*\)/')" 2>/dev/null || :
fi &&
exec git update-index --remove -- "$4"
;;
#
# Added in one.
#
".$2.")
# the other side did not add and we added so there is nothing
# to be done, except making the path merged.
exec git update-index --add --cacheinfo "$6" "$2" "$4"
;;
"..$3")
echo "Adding $4"
if test -f "$4"
then
echo "ERROR: untracked $4 is overwritten by the merge." >&2
exit 1
fi
git update-index --add --cacheinfo "$7" "$3" "$4" &&
exec git checkout-index -u -f -- "$4"
;;
#
# Added in both, identically (check for same permissions).
#
".$3$2")
if test "$6" != "$7"
then
echo "ERROR: File $4 added identically in both branches," >&2
echo "ERROR: but permissions conflict $6->$7." >&2
exit 1
fi
echo "Adding $4"
git update-index --add --cacheinfo "$6" "$2" "$4" &&
exec git checkout-index -u -f -- "$4"
;;
#
# Modified in both, but differently.
#
"$1$2$3" | ".$2$3")
case ",$6,$7," in
*,120000,*)
echo "ERROR: $4: Not merging symbolic link changes." >&2
exit 1
;;
*,160000,*)
echo "ERROR: $4: Not merging conflicting submodule changes." >&2
exit 1
;;
esac
src1=$(git unpack-file $2)
src2=$(git unpack-file $3)
case "$1" in
'')
echo "Added $4 in both, but differently."
orig=$(git unpack-file $(git hash-object /dev/null))
;;
*)
echo "Auto-merging $4"
orig=$(git unpack-file $1)
;;
esac
git merge-file "$src1" "$orig" "$src2"
ret=$?
msg=
if test $ret != 0 || test -z "$1"
then
msg='content conflict'
ret=1
fi
# Create the working tree file, using "our tree" version from the
# index, and then store the result of the merge.
git checkout-index -f --stage=2 -- "$4" && cat "$src1" >"$4" || exit 1
rm -f -- "$orig" "$src1" "$src2"
if test "$6" != "$7"
then
if test -n "$msg"
then
msg="$msg, "
fi
msg="${msg}permissions conflict: $5->$6,$7"
ret=1
fi
if test $ret != 0
then
echo "ERROR: $msg in $4" >&2
exit 1
fi
exec git update-index -- "$4"
;;
*)
echo "ERROR: $4: Not handling case $1 -> $2 -> $3" >&2
;;
esac
exit 1

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,54 @@
#!/bin/sh
#
# Copyright (c) 2005 Linus Torvalds
# Copyright (c) 2005 Junio C Hamano
#
# Resolve two trees, using enhanced multi-base read-tree.
# The first parameters up to -- are merge bases; the rest are heads.
bases= head= remotes= sep_seen=
for arg
do
case ",$sep_seen,$head,$arg," in
*,--,)
sep_seen=yes
;;
,yes,,*)
head=$arg
;;
,yes,*)
remotes="$remotes$arg "
;;
*)
bases="$bases$arg "
;;
esac
done
# Give up if we are given two or more remotes -- not handling octopus.
case "$remotes" in
?*' '?*)
exit 2 ;;
esac
# Give up if this is a baseless merge.
if test '' = "$bases"
then
exit 2
fi
git update-index -q --refresh
git read-tree -u -m --aggressive $bases $head $remotes || exit 2
echo "Trying simple merge."
if result_tree=$(git write-tree 2>/dev/null)
then
exit 0
else
echo "Simple merge failed, trying Automatic merge."
if git merge-index -o git-merge-one-file -a
then
exit 0
else
exit 1
fi
fi

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,516 @@
#!/bin/sh
#
# This program resolves merge conflicts in git
#
# Copyright (c) 2006 Theodore Y. Ts'o
# Copyright (c) 2009-2016 David Aguilar
#
# This file is licensed under the GPL v2, or a later version
# at the discretion of Junio C Hamano.
#
USAGE='[--tool=tool] [--tool-help] [-y|--no-prompt|--prompt] [-g|--gui|--no-gui] [-O<orderfile>] [file to merge] ...'
SUBDIRECTORY_OK=Yes
NONGIT_OK=Yes
OPTIONS_SPEC=
TOOL_MODE=merge
. git-sh-setup
. git-mergetool--lib
# Returns true if the mode reflects a symlink
is_symlink () {
test "$1" = 120000
}
is_submodule () {
test "$1" = 160000
}
local_present () {
test -n "$local_mode"
}
remote_present () {
test -n "$remote_mode"
}
base_present () {
test -n "$base_mode"
}
mergetool_tmpdir_init () {
if test "$(git config --bool mergetool.writeToTemp)" != true
then
MERGETOOL_TMPDIR=.
return 0
fi
if MERGETOOL_TMPDIR=$(mktemp -d -t "git-mergetool-XXXXXX" 2>/dev/null)
then
return 0
fi
die "error: mktemp is needed when 'mergetool.writeToTemp' is true"
}
cleanup_temp_files () {
if test "$1" = --save-backup
then
rm -rf -- "$MERGED.orig"
test -e "$BACKUP" && mv -- "$BACKUP" "$MERGED.orig"
rm -f -- "$LOCAL" "$REMOTE" "$BASE"
else
rm -f -- "$LOCAL" "$REMOTE" "$BASE" "$BACKUP"
fi
if test "$MERGETOOL_TMPDIR" != "."
then
rmdir "$MERGETOOL_TMPDIR"
fi
}
describe_file () {
mode="$1"
branch="$2"
file="$3"
printf " {%s}: " "$branch"
if test -z "$mode"
then
echo "deleted"
elif is_symlink "$mode"
then
echo "a symbolic link -> '$(cat "$file")'"
elif is_submodule "$mode"
then
echo "submodule commit $file"
elif base_present
then
echo "modified file"
else
echo "created file"
fi
}
resolve_symlink_merge () {
while true
do
printf "Use (l)ocal or (r)emote, or (a)bort? "
read ans || return 1
case "$ans" in
[lL]*)
git checkout-index -f --stage=2 -- "$MERGED"
git add -- "$MERGED"
cleanup_temp_files --save-backup
return 0
;;
[rR]*)
git checkout-index -f --stage=3 -- "$MERGED"
git add -- "$MERGED"
cleanup_temp_files --save-backup
return 0
;;
[aA]*)
return 1
;;
esac
done
}
resolve_deleted_merge () {
while true
do
if base_present
then
printf "Use (m)odified or (d)eleted file, or (a)bort? "
else
printf "Use (c)reated or (d)eleted file, or (a)bort? "
fi
read ans || return 1
case "$ans" in
[mMcC]*)
git add -- "$MERGED"
if test "$merge_keep_backup" = "true"
then
cleanup_temp_files --save-backup
else
cleanup_temp_files
fi
return 0
;;
[dD]*)
git rm -- "$MERGED" > /dev/null
cleanup_temp_files
return 0
;;
[aA]*)
if test "$merge_keep_temporaries" = "false"
then
cleanup_temp_files
fi
return 1
;;
esac
done
}
resolve_submodule_merge () {
while true
do
printf "Use (l)ocal or (r)emote, or (a)bort? "
read ans || return 1
case "$ans" in
[lL]*)
if ! local_present
then
if test -n "$(git ls-tree HEAD -- "$MERGED")"
then
# Local isn't present, but it's a subdirectory
git ls-tree --full-name -r HEAD -- "$MERGED" |
git update-index --index-info || exit $?
else
test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
git update-index --force-remove "$MERGED"
cleanup_temp_files --save-backup
fi
elif is_submodule "$local_mode"
then
stage_submodule "$MERGED" "$local_sha1"
else
git checkout-index -f --stage=2 -- "$MERGED"
git add -- "$MERGED"
fi
return 0
;;
[rR]*)
if ! remote_present
then
if test -n "$(git ls-tree MERGE_HEAD -- "$MERGED")"
then
# Remote isn't present, but it's a subdirectory
git ls-tree --full-name -r MERGE_HEAD -- "$MERGED" |
git update-index --index-info || exit $?
else
test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
git update-index --force-remove "$MERGED"
fi
elif is_submodule "$remote_mode"
then
! is_submodule "$local_mode" &&
test -e "$MERGED" &&
mv -- "$MERGED" "$BACKUP"
stage_submodule "$MERGED" "$remote_sha1"
else
test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
git checkout-index -f --stage=3 -- "$MERGED"
git add -- "$MERGED"
fi
cleanup_temp_files --save-backup
return 0
;;
[aA]*)
return 1
;;
esac
done
}
stage_submodule () {
path="$1"
submodule_sha1="$2"
mkdir -p "$path" ||
die "fatal: unable to create directory for module at $path"
# Find $path relative to work tree
work_tree_root=$(cd_to_toplevel && pwd)
work_rel_path=$(cd "$path" &&
GIT_WORK_TREE="${work_tree_root}" git rev-parse --show-prefix
)
test -n "$work_rel_path" ||
die "fatal: unable to get path of module $path relative to work tree"
git update-index --add --replace --cacheinfo 160000 "$submodule_sha1" "${work_rel_path%/}" || die
}
checkout_staged_file () {
tmpfile=$(expr \
"$(git checkout-index --temp --stage="$1" "$2" 2>/dev/null)" \
: '\([^ ]*\) ')
if test $? -eq 0 && test -n "$tmpfile"
then
mv -- "$(git rev-parse --show-cdup)$tmpfile" "$3"
else
>"$3"
fi
}
merge_file () {
MERGED="$1"
f=$(git ls-files -u -- "$MERGED")
if test -z "$f"
then
if test ! -f "$MERGED"
then
echo "$MERGED: file not found"
else
echo "$MERGED: file does not need merging"
fi
return 1
fi
if BASE=$(expr "$MERGED" : '\(.*\)\.[^/]*$')
then
ext=$(expr "$MERGED" : '.*\(\.[^/]*\)$')
else
BASE=$MERGED
ext=
fi
mergetool_tmpdir_init
if test "$MERGETOOL_TMPDIR" != "."
then
# If we're using a temporary directory then write to the
# top-level of that directory.
BASE=${BASE##*/}
fi
BACKUP="$MERGETOOL_TMPDIR/${BASE}_BACKUP_$$$ext"
LOCAL="$MERGETOOL_TMPDIR/${BASE}_LOCAL_$$$ext"
REMOTE="$MERGETOOL_TMPDIR/${BASE}_REMOTE_$$$ext"
BASE="$MERGETOOL_TMPDIR/${BASE}_BASE_$$$ext"
base_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}')
local_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}')
remote_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}')
if is_submodule "$local_mode" || is_submodule "$remote_mode"
then
echo "Submodule merge conflict for '$MERGED':"
local_sha1=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $2;}')
remote_sha1=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $2;}')
describe_file "$local_mode" "local" "$local_sha1"
describe_file "$remote_mode" "remote" "$remote_sha1"
resolve_submodule_merge
return
fi
if test -f "$MERGED"
then
mv -- "$MERGED" "$BACKUP"
cp -- "$BACKUP" "$MERGED"
fi
# Create a parent directory to handle delete/delete conflicts
# where the base's directory no longer exists.
mkdir -p "$(dirname "$MERGED")"
checkout_staged_file 1 "$MERGED" "$BASE"
checkout_staged_file 2 "$MERGED" "$LOCAL"
checkout_staged_file 3 "$MERGED" "$REMOTE"
if test -z "$local_mode" || test -z "$remote_mode"
then
echo "Deleted merge conflict for '$MERGED':"
describe_file "$local_mode" "local" "$LOCAL"
describe_file "$remote_mode" "remote" "$REMOTE"
resolve_deleted_merge
status=$?
rmdir -p "$(dirname "$MERGED")" 2>/dev/null
return $status
fi
if is_symlink "$local_mode" || is_symlink "$remote_mode"
then
echo "Symbolic link merge conflict for '$MERGED':"
describe_file "$local_mode" "local" "$LOCAL"
describe_file "$remote_mode" "remote" "$REMOTE"
resolve_symlink_merge
return
fi
echo "Normal merge conflict for '$MERGED':"
describe_file "$local_mode" "local" "$LOCAL"
describe_file "$remote_mode" "remote" "$REMOTE"
if test "$guessed_merge_tool" = true || test "$prompt" = true
then
printf "Hit return to start merge resolution tool (%s): " "$merge_tool"
read ans || return 1
fi
if base_present
then
present=true
else
present=false
fi
if ! run_merge_tool "$merge_tool" "$present"
then
echo "merge of $MERGED failed" 1>&2
mv -- "$BACKUP" "$MERGED"
if test "$merge_keep_temporaries" = "false"
then
cleanup_temp_files
fi
return 1
fi
if test "$merge_keep_backup" = "true"
then
mv -- "$BACKUP" "$MERGED.orig"
else
rm -- "$BACKUP"
fi
git add -- "$MERGED"
cleanup_temp_files
return 0
}
prompt_after_failed_merge () {
while true
do
printf "Continue merging other unresolved paths [y/n]? "
read ans || return 1
case "$ans" in
[yY]*)
return 0
;;
[nN]*)
return 1
;;
esac
done
}
print_noop_and_exit () {
echo "No files need merging"
exit 0
}
main () {
prompt=$(git config --bool mergetool.prompt)
gui_tool=false
guessed_merge_tool=false
orderfile=
while test $# != 0
do
case "$1" in
--tool-help=*)
TOOL_MODE=${1#--tool-help=}
show_tool_help
;;
--tool-help)
show_tool_help
;;
-t|--tool*)
case "$#,$1" in
*,*=*)
merge_tool=$(expr "z$1" : 'z-[^=]*=\(.*\)')
;;
1,*)
usage ;;
*)
merge_tool="$2"
shift ;;
esac
;;
--no-gui)
gui_tool=false
;;
-g|--gui)
gui_tool=true
;;
-y|--no-prompt)
prompt=false
;;
--prompt)
prompt=true
;;
-O*)
orderfile="${1#-O}"
;;
--)
shift
break
;;
-*)
usage
;;
*)
break
;;
esac
shift
done
git_dir_init
require_work_tree
if test -z "$merge_tool"
then
# Check if a merge tool has been configured
merge_tool=$(get_configured_merge_tool $gui_tool)
# Try to guess an appropriate merge tool if no tool has been set.
if test -z "$merge_tool"
then
merge_tool=$(guess_merge_tool) || exit
guessed_merge_tool=true
fi
fi
merge_keep_backup="$(git config --bool mergetool.keepBackup || echo true)"
merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)"
prefix=$(git rev-parse --show-prefix) || exit 1
cd_to_toplevel
if test -n "$orderfile"
then
orderfile=$(
git rev-parse --prefix "$prefix" -- "$orderfile" |
sed -e 1d
)
fi
if test $# -eq 0 && test -e "$GIT_DIR/MERGE_RR"
then
set -- $(git rerere remaining)
if test $# -eq 0
then
print_noop_and_exit
fi
elif test $# -ge 0
then
# rev-parse provides the -- needed for 'set'
eval "set $(git rev-parse --sq --prefix "$prefix" -- "$@")"
fi
files=$(git -c core.quotePath=false \
diff --name-only --diff-filter=U \
${orderfile:+"-O$orderfile"} -- "$@")
if test -z "$files"
then
print_noop_and_exit
fi
printf "Merging:\n"
printf "%s\n" "$files"
rc=0
set -- $files
while test $# -ne 0
do
printf "\n"
if ! merge_file "$1"
then
rc=1
test $# -ne 1 && prompt_after_failed_merge || exit 1
fi
shift
done
exit $rc
}
main "$@"

View File

@ -0,0 +1,439 @@
# git-mergetool--lib is a shell library for common merge tool functions
: ${MERGE_TOOLS_DIR=$(git --exec-path)/mergetools}
IFS='
'
mode_ok () {
if diff_mode
then
can_diff
elif merge_mode
then
can_merge
else
false
fi
}
is_available () {
merge_tool_path=$(translate_merge_tool_path "$1") &&
type "$merge_tool_path" >/dev/null 2>&1
}
list_config_tools () {
section=$1
line_prefix=${2:-}
git config --get-regexp $section'\..*\.cmd' |
while read -r key value
do
toolname=${key#$section.}
toolname=${toolname%.cmd}
printf "%s%s\n" "$line_prefix" "$toolname"
done
}
show_tool_names () {
condition=${1:-true} per_line_prefix=${2:-} preamble=${3:-}
not_found_msg=${4:-}
extra_content=${5:-}
shown_any=
( cd "$MERGE_TOOLS_DIR" && ls ) | {
while read toolname
do
if setup_tool "$toolname" 2>/dev/null &&
(eval "$condition" "$toolname")
then
if test -n "$preamble"
then
printf "%s\n" "$preamble"
preamble=
fi
shown_any=yes
printf "%s%s\n" "$per_line_prefix" "$toolname"
fi
done
if test -n "$extra_content"
then
if test -n "$preamble"
then
# Note: no '\n' here since we don't want a
# blank line if there is no initial content.
printf "%s" "$preamble"
preamble=
fi
shown_any=yes
printf "\n%s\n" "$extra_content"
fi
if test -n "$preamble" && test -n "$not_found_msg"
then
printf "%s\n" "$not_found_msg"
fi
test -n "$shown_any"
}
}
diff_mode() {
test "$TOOL_MODE" = diff
}
merge_mode() {
test "$TOOL_MODE" = merge
}
translate_merge_tool_path () {
echo "$1"
}
check_unchanged () {
if test "$MERGED" -nt "$BACKUP"
then
return 0
else
while true
do
echo "$MERGED seems unchanged."
printf "Was the merge successful [y/n]? "
read answer || return 1
case "$answer" in
y*|Y*) return 0 ;;
n*|N*) return 1 ;;
esac
done
fi
}
valid_tool () {
setup_tool "$1" && return 0
cmd=$(get_merge_tool_cmd "$1")
test -n "$cmd"
}
setup_user_tool () {
merge_tool_cmd=$(get_merge_tool_cmd "$tool")
test -n "$merge_tool_cmd" || return 1
diff_cmd () {
( eval $merge_tool_cmd )
}
merge_cmd () {
( eval $merge_tool_cmd )
}
}
setup_tool () {
tool="$1"
# Fallback definitions, to be overridden by tools.
can_merge () {
return 0
}
can_diff () {
return 0
}
diff_cmd () {
return 1
}
merge_cmd () {
return 1
}
translate_merge_tool_path () {
echo "$1"
}
# Most tools' exit codes cannot be trusted, so By default we ignore
# their exit code and check the merged file's modification time in
# check_unchanged() to determine whether or not the merge was
# successful. The return value from run_merge_cmd, by default, is
# determined by check_unchanged().
#
# When a tool's exit code can be trusted then the return value from
# run_merge_cmd is simply the tool's exit code, and check_unchanged()
# is not called.
#
# The return value of exit_code_trustable() tells us whether or not we
# can trust the tool's exit code.
#
# User-defined and built-in tools default to false.
# Built-in tools advertise that their exit code is trustable by
# redefining exit_code_trustable() to true.
exit_code_trustable () {
false
}
if ! test -f "$MERGE_TOOLS_DIR/$tool"
then
setup_user_tool
return $?
fi
# Load the redefined functions
. "$MERGE_TOOLS_DIR/$tool"
# Now let the user override the default command for the tool. If
# they have not done so then this will return 1 which we ignore.
setup_user_tool
if merge_mode && ! can_merge
then
echo "error: '$tool' can not be used to resolve merges" >&2
return 1
elif diff_mode && ! can_diff
then
echo "error: '$tool' can only be used to resolve merges" >&2
return 1
fi
return 0
}
get_merge_tool_cmd () {
merge_tool="$1"
if diff_mode
then
git config "difftool.$merge_tool.cmd" ||
git config "mergetool.$merge_tool.cmd"
else
git config "mergetool.$merge_tool.cmd"
fi
}
trust_exit_code () {
if git config --bool "mergetool.$1.trustExitCode"
then
:; # OK
elif exit_code_trustable
then
echo true
else
echo false
fi
}
# Entry point for running tools
run_merge_tool () {
# If GIT_PREFIX is empty then we cannot use it in tools
# that expect to be able to chdir() to its value.
GIT_PREFIX=${GIT_PREFIX:-.}
export GIT_PREFIX
merge_tool_path=$(get_merge_tool_path "$1") || exit
base_present="$2"
# Bring tool-specific functions into scope
setup_tool "$1" || return 1
if merge_mode
then
run_merge_cmd "$1"
else
run_diff_cmd "$1"
fi
}
# Run a either a configured or built-in diff tool
run_diff_cmd () {
diff_cmd "$1"
}
# Run a either a configured or built-in merge tool
run_merge_cmd () {
mergetool_trust_exit_code=$(trust_exit_code "$1")
if test "$mergetool_trust_exit_code" = "true"
then
merge_cmd "$1"
else
touch "$BACKUP"
merge_cmd "$1"
check_unchanged
fi
}
list_merge_tool_candidates () {
if merge_mode
then
tools="tortoisemerge"
else
tools="kompare"
fi
if test -n "$DISPLAY"
then
if test -n "$GNOME_DESKTOP_SESSION_ID"
then
tools="meld opendiff kdiff3 tkdiff xxdiff $tools"
else
tools="opendiff kdiff3 tkdiff xxdiff meld $tools"
fi
tools="$tools gvimdiff diffuse diffmerge ecmerge"
tools="$tools p4merge araxis bc codecompare"
fi
case "${VISUAL:-$EDITOR}" in
*vim*)
tools="$tools vimdiff emerge"
;;
*)
tools="$tools emerge vimdiff"
;;
esac
}
show_tool_help () {
tool_opt="'git ${TOOL_MODE}tool --tool=<tool>'"
tab=' '
LF='
'
any_shown=no
cmd_name=${TOOL_MODE}tool
config_tools=$({
diff_mode && list_config_tools difftool "$tab$tab"
list_config_tools mergetool "$tab$tab"
} | sort)
extra_content=
if test -n "$config_tools"
then
extra_content="${tab}user-defined:${LF}$config_tools"
fi
show_tool_names 'mode_ok && is_available' "$tab$tab" \
"$tool_opt may be set to one of the following:" \
"No suitable tool for 'git $cmd_name --tool=<tool>' found." \
"$extra_content" &&
any_shown=yes
show_tool_names 'mode_ok && ! is_available' "$tab$tab" \
"${LF}The following tools are valid, but not currently available:" &&
any_shown=yes
if test "$any_shown" = yes
then
echo
echo "Some of the tools listed above only work in a windowed"
echo "environment. If run in a terminal-only session, they will fail."
fi
exit 0
}
guess_merge_tool () {
list_merge_tool_candidates
cat >&2 <<-EOF
This message is displayed because '$TOOL_MODE.tool' is not configured.
See 'git ${TOOL_MODE}tool --tool-help' or 'git help config' for more details.
'git ${TOOL_MODE}tool' will now attempt to use one of the following tools:
$tools
EOF
# Loop over each candidate and stop when a valid merge tool is found.
IFS=' '
for tool in $tools
do
is_available "$tool" && echo "$tool" && return 0
done
echo >&2 "No known ${TOOL_MODE} tool is available."
return 1
}
get_configured_merge_tool () {
# If first argument is true, find the guitool instead
if test "$1" = true
then
gui_prefix=gui
fi
# Diff mode first tries diff.(gui)tool and falls back to merge.(gui)tool.
# Merge mode only checks merge.(gui)tool
if diff_mode
then
merge_tool=$(git config diff.${gui_prefix}tool || git config merge.${gui_prefix}tool)
else
merge_tool=$(git config merge.${gui_prefix}tool)
fi
if test -n "$merge_tool" && ! valid_tool "$merge_tool"
then
echo >&2 "git config option $TOOL_MODE.${gui_prefix}tool set to unknown tool: $merge_tool"
echo >&2 "Resetting to default..."
return 1
fi
echo "$merge_tool"
}
get_merge_tool_path () {
# A merge tool has been set, so verify that it's valid.
merge_tool="$1"
if ! valid_tool "$merge_tool"
then
echo >&2 "Unknown merge tool $merge_tool"
exit 1
fi
if diff_mode
then
merge_tool_path=$(git config difftool."$merge_tool".path ||
git config mergetool."$merge_tool".path)
else
merge_tool_path=$(git config mergetool."$merge_tool".path)
fi
if test -z "$merge_tool_path"
then
merge_tool_path=$(translate_merge_tool_path "$merge_tool")
fi
if test -z "$(get_merge_tool_cmd "$merge_tool")" &&
! type "$merge_tool_path" >/dev/null 2>&1
then
echo >&2 "The $TOOL_MODE tool $merge_tool is not available as"\
"'$merge_tool_path'"
exit 1
fi
echo "$merge_tool_path"
}
get_merge_tool () {
# Check if a merge tool has been configured
merge_tool=$(get_configured_merge_tool)
# Try to guess an appropriate merge tool if no tool has been set.
if test -z "$merge_tool"
then
merge_tool=$(guess_merge_tool) || exit
fi
echo "$merge_tool"
}
mergetool_find_win32_cmd () {
executable=$1
sub_directory=$2
# Use $executable if it exists in $PATH
if type -p "$executable" >/dev/null 2>&1
then
printf '%s' "$executable"
return
fi
# Look for executable in the typical locations
for directory in $(env | grep -Ei '^PROGRAM(FILES(\(X86\))?|W6432)=' |
cut -d '=' -f 2- | sort -u)
do
if test -n "$directory" && test -x "$directory/$sub_directory/$executable"
then
printf '%s' "$directory/$sub_directory/$executable"
return
fi
done
printf '%s' "$executable"
}

Binary file not shown.

Binary file not shown.

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