diff options
Diffstat (limited to 'contrib')
36 files changed, 344 insertions, 8411 deletions
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index b060b6ff6e..86a13fca28 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -29,6 +29,8 @@ # tell the completion to use commit completion. This also works with aliases # of form "!sh -c '...'". For example, "!sh -c ': git commit ; ... '". # +# Compatible with bash 3.2.57. +# # You can set the following environment variables to influence the behavior of # the completion routines: # @@ -280,6 +282,43 @@ __gitcomp () esac } +# Clear the variables caching builtins' options when (re-)sourcing +# the completion script. +unset $(set |sed -ne 's/^\(__gitcomp_builtin_[a-zA-Z0-9_][a-zA-Z0-9_]*\)=.*/\1/p') 2>/dev/null + +# This function is equivalent to +# +# __gitcomp "$(git xxx --git-completion-helper) ..." +# +# except that the output is cached. Accept 1-3 arguments: +# 1: the git command to execute, this is also the cache key +# 2: extra options to be added on top (e.g. negative forms) +# 3: options to be excluded +__gitcomp_builtin () +{ + # spaces must be replaced with underscore for multi-word + # commands, e.g. "git remote add" becomes remote_add. + local cmd="$1" + local incl="$2" + local excl="$3" + + local var=__gitcomp_builtin_"${cmd/-/_}" + local options + eval "options=\$$var" + + if [ -z "$options" ]; then + # leading and trailing spaces are significant to make + # option removal work correctly. + options=" $(__git ${cmd/_/ } --git-completion-helper) $incl " + for i in $excl; do + options="${options/ $i / }" + done + eval "$var=\"$options\"" + fi + + __gitcomp "$options" +} + # Variation of __gitcomp_nl () that appends to the existing list of # completion candidates, COMPREPLY. __gitcomp_nl_append () @@ -351,12 +390,7 @@ __git_index_files () local root="${2-.}" file __git_ls_files_helper "$root" "$1" | - while read -r file; do - case "$file" in - ?*/*) echo "${file%%/*}" ;; - *) echo "$file" ;; - esac - done | sort | uniq + cut -f1 -d/ | sort | uniq } # Lists branches from the local repository. @@ -439,7 +473,7 @@ __git_refs () track="" ;; *) - for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do + for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD; do case "$i" in $match*) if [ -e "$dir/$i" ]; then @@ -1073,12 +1107,13 @@ __git_count_arguments () } __git_whitespacelist="nowarn warn error error-all fix" +__git_am_inprogress_options="--skip --continue --resolved --abort --quit --show-current-patch" _git_am () { __git_find_repo_path if [ -d "$__git_repo_path"/rebase-apply ]; then - __gitcomp "--skip --continue --resolved --abort" + __gitcomp "$__git_am_inprogress_options" return fi case "$cur" in @@ -1087,12 +1122,8 @@ _git_am () return ;; --*) - __gitcomp " - --3way --committer-date-is-author-date --ignore-date - --ignore-whitespace --ignore-space-change - --interactive --keep --no-utf8 --signoff --utf8 - --whitespace= --scissors - " + __gitcomp_builtin am "--no-utf8" \ + "$__git_am_inprogress_options" return esac } @@ -1105,14 +1136,7 @@ _git_apply () return ;; --*) - __gitcomp " - --stat --numstat --summary --check --index - --cached --index-info --reverse --reject --unidiff-zero - --apply --no-add --exclude= - --ignore-whitespace --ignore-space-change - --whitespace= --inaccurate-eof --verbose - --recount --directory= - " + __gitcomp_builtin apply return esac } @@ -1121,10 +1145,7 @@ _git_add () { case "$cur" in --*) - __gitcomp " - --interactive --refresh --patch --update --dry-run - --ignore-errors --intent-to-add --force --edit --chmod= - " + __gitcomp_builtin add return esac @@ -1201,12 +1222,8 @@ _git_branch () __git_complete_refs --cur="${cur##--set-upstream-to=}" ;; --*) - __gitcomp " - --color --no-color --verbose --abbrev= --no-abbrev - --track --no-track --contains --no-contains --merged --no-merged - --set-upstream-to= --edit-description --list - --unset-upstream --delete --move --copy --remotes - --column --no-column --sort= --points-at + __gitcomp_builtin branch "--no-color --no-abbrev + --no-track --no-column " ;; *) @@ -1248,11 +1265,7 @@ _git_checkout () __gitcomp "diff3 merge" "" "${cur##--conflict=}" ;; --*) - __gitcomp " - --quiet --ours --theirs --track --no-track --merge - --conflict= --orphan --patch --detach --ignore-skip-worktree-bits - --recurse-submodules --no-recurse-submodules - " + __gitcomp_builtin checkout "--no-track --no-recurse-submodules" ;; *) # check if --track, --no-track, or --no-guess was specified @@ -1269,19 +1282,28 @@ _git_checkout () _git_cherry () { + case "$cur" in + --*) + __gitcomp_builtin cherry + return + esac + __git_complete_refs } +__git_cherry_pick_inprogress_options="--continue --quit --abort" + _git_cherry_pick () { __git_find_repo_path if [ -f "$__git_repo_path"/CHERRY_PICK_HEAD ]; then - __gitcomp "--continue --quit --abort" + __gitcomp "$__git_cherry_pick_inprogress_options" return fi case "$cur" in --*) - __gitcomp "--edit --no-commit --signoff --strategy= --mainline" + __gitcomp_builtin cherry-pick "" \ + "$__git_cherry_pick_inprogress_options" ;; *) __git_complete_refs @@ -1293,7 +1315,7 @@ _git_clean () { case "$cur" in --*) - __gitcomp "--dry-run --quiet" + __gitcomp_builtin clean return ;; esac @@ -1306,26 +1328,7 @@ _git_clone () { case "$cur" in --*) - __gitcomp " - --local - --no-hardlinks - --shared - --reference - --quiet - --no-checkout - --bare - --mirror - --origin - --upload-pack - --template= - --depth - --single-branch - --no-tags - --branch - --recurse-submodules - --no-single-branch - --shallow-submodules - " + __gitcomp_builtin clone "--no-single-branch" return ;; esac @@ -1358,16 +1361,7 @@ _git_commit () return ;; --*) - __gitcomp " - --all --author= --signoff --verify --no-verify - --edit --no-edit - --amend --include --only --interactive - --dry-run --reuse-message= --reedit-message= - --reset-author --file= --message= --template= - --cleanup= --untracked-files --untracked-files= - --verbose --quiet --fixup= --squash= - --patch --short --date --allow-empty - " + __gitcomp_builtin commit "--no-edit --verify" return esac @@ -1383,11 +1377,7 @@ _git_describe () { case "$cur" in --*) - __gitcomp " - --all --tags --contains --abbrev= --candidates= - --exact-match --debug --long --match --always --first-parent - --exclude --dirty --broken - " + __gitcomp_builtin describe return esac __git_complete_refs @@ -1412,7 +1402,7 @@ __git_diff_common_options="--stat --numstat --shortstat --summary --dirstat --dirstat= --dirstat-by-file --dirstat-by-file= --cumulative --diff-algorithm= - --submodule --submodule= + --submodule --submodule= --ignore-submodules " _git_diff () @@ -1453,11 +1443,11 @@ _git_difftool () return ;; --*) - __gitcomp "--cached --staged --pickaxe-all --pickaxe-regex - --base --ours --theirs - --no-renames --diff-filter= --find-copies-harder - --relative --ignore-submodules - --tool=" + __gitcomp_builtin difftool "$__git_diff_common_options + --base --cached --ours --theirs + --pickaxe-all --pickaxe-regex + --relative --staged + " return ;; esac @@ -1466,12 +1456,6 @@ _git_difftool () __git_fetch_recurse_submodules="yes on-demand no" -__git_fetch_options=" - --quiet --verbose --append --upload-pack --force --keep --depth= - --tags --no-tags --all --prune --dry-run --recurse-submodules= - --unshallow --update-shallow -" - _git_fetch () { case "$cur" in @@ -1480,7 +1464,7 @@ _git_fetch () return ;; --*) - __gitcomp "$__git_fetch_options" + __gitcomp_builtin fetch "--no-tags" return ;; esac @@ -1517,20 +1501,7 @@ _git_fsck () { case "$cur" in --*) - __gitcomp " - --tags --root --unreachable --cache --no-reflogs --full - --strict --verbose --lost-found --name-objects - " - return - ;; - esac -} - -_git_gc () -{ - case "$cur" in - --*) - __gitcomp "--prune --aggressive" + __gitcomp_builtin fsck "--no-reflogs" return ;; esac @@ -1586,21 +1557,7 @@ _git_grep () case "$cur" in --*) - __gitcomp " - --cached - --text --ignore-case --word-regexp --invert-match - --full-name --line-number - --extended-regexp --basic-regexp --fixed-strings - --perl-regexp - --threads - --files-with-matches --name-only - --files-without-match - --max-depth - --count - --and --or --not --all-match - --break --heading --show-function --function-context - --untracked --no-index - " + __gitcomp_builtin grep return ;; esac @@ -1618,7 +1575,7 @@ _git_help () { case "$cur" in --*) - __gitcomp "--all --guides --info --man --web" + __gitcomp_builtin help return ;; esac @@ -1641,7 +1598,7 @@ _git_init () return ;; --*) - __gitcomp "--quiet --bare --template= --shared --shared=" + __gitcomp_builtin init return ;; esac @@ -1651,13 +1608,7 @@ _git_ls_files () { case "$cur" in --*) - __gitcomp "--cached --deleted --modified --others --ignored - --stage --directory --no-empty-directory --unmerged - --killed --exclude= --exclude-from= - --exclude-per-directory= --exclude-standard - --error-unmatch --with-tree= --full-name - --abbrev --ignored --exclude-per-directory - " + __gitcomp_builtin ls-files "--no-empty-directory" return ;; esac @@ -1671,7 +1622,7 @@ _git_ls_remote () { case "$cur" in --*) - __gitcomp "--heads --tags --refs --get-url --symref" + __gitcomp_builtin ls-remote return ;; esac @@ -1680,6 +1631,13 @@ _git_ls_remote () _git_ls_tree () { + case "$cur" in + --*) + __gitcomp_builtin ls-tree + return + ;; + esac + __git_complete_file } @@ -1795,22 +1753,18 @@ _git_log () __git_complete_revlist } -# Common merge options shared by git-merge(1) and git-pull(1). -__git_merge_options=" - --no-commit --no-stat --log --no-log --squash --strategy - --commit --stat --no-squash --ff --no-ff --ff-only --edit --no-edit - --verify-signatures --no-verify-signatures --gpg-sign - --quiet --verbose --progress --no-progress -" - _git_merge () { __git_complete_strategy && return case "$cur" in --*) - __gitcomp "$__git_merge_options - --rerere-autoupdate --no-rerere-autoupdate --abort --continue" + __gitcomp_builtin merge "--no-rerere-autoupdate + --no-commit --no-edit --no-ff + --no-log --no-progress + --no-squash --no-stat + --no-verify-signatures + " return esac __git_complete_refs @@ -1834,7 +1788,7 @@ _git_merge_base () { case "$cur" in --*) - __gitcomp "--octopus --independent --is-ancestor --fork-point" + __gitcomp_builtin merge-base return ;; esac @@ -1845,7 +1799,7 @@ _git_mv () { case "$cur" in --*) - __gitcomp "--dry-run" + __gitcomp_builtin mv return ;; esac @@ -1859,19 +1813,14 @@ _git_mv () fi } -_git_name_rev () -{ - __gitcomp "--tags --all --stdin" -} - _git_notes () { - local subcommands='add append copy edit list prune remove show' + local subcommands='add append copy edit get-ref list merge prune remove show' local subcommand="$(__git_find_on_cmdline "$subcommands")" case "$subcommand,$cur" in ,--*) - __gitcomp '--ref' + __gitcomp_builtin notes ;; ,*) case "$prev" in @@ -1883,21 +1832,14 @@ _git_notes () ;; esac ;; - add,--reuse-message=*|append,--reuse-message=*|\ - add,--reedit-message=*|append,--reedit-message=*) + *,--reuse-message=*|*,--reedit-message=*) __git_complete_refs --cur="${cur#*=}" ;; - add,--*|append,--*) - __gitcomp '--file= --message= --reedit-message= - --reuse-message=' - ;; - copy,--*) - __gitcomp '--stdin' - ;; - prune,--*) - __gitcomp '--dry-run --verbose' + *,--*) + __gitcomp_builtin notes_$subcommand ;; - prune,*) + prune,*|get-ref,*) + # this command does not take a ref, do not complete it ;; *) case "$prev" in @@ -1921,12 +1863,11 @@ _git_pull () return ;; --*) - __gitcomp " - --rebase --no-rebase - --autostash --no-autostash - $__git_merge_options - $__git_fetch_options - " + __gitcomp_builtin pull "--no-autostash --no-commit --no-edit + --no-ff --no-log --no-progress --no-rebase + --no-squash --no-stat --no-tags + --no-verify-signatures" + return ;; esac @@ -1977,12 +1918,7 @@ _git_push () return ;; --*) - __gitcomp " - --all --mirror --tags --dry-run --force --verbose - --quiet --prune --delete --follow-tags - --receive-pack= --repo= --set-upstream - --force-with-lease --force-with-lease= --recurse-submodules= - " + __gitcomp_builtin push return ;; esac @@ -1993,11 +1929,11 @@ _git_rebase () { __git_find_repo_path if [ -f "$__git_repo_path"/rebase-merge/interactive ]; then - __gitcomp "--continue --skip --abort --quit --edit-todo" + __gitcomp "--continue --skip --abort --quit --edit-todo --show-current-patch" return elif [ -d "$__git_repo_path"/rebase-apply ] || \ [ -d "$__git_repo_path"/rebase-merge ]; then - __gitcomp "--continue --skip --abort --quit" + __gitcomp "--continue --skip --abort --quit --show-current-patch" return fi __git_complete_strategy && return @@ -2017,6 +1953,7 @@ _git_rebase () --autostash --no-autostash --verify --no-verify --keep-empty --root --force-rebase --no-ff + --rerere-autoupdate --exec " @@ -2082,7 +2019,7 @@ _git_send_email () --compose --confirm= --dry-run --envelope-sender --from --identity --in-reply-to --no-chain-reply-to --no-signed-off-by-cc - --no-suppress-from --no-thread --quiet + --no-suppress-from --no-thread --quiet --reply-to --signed-off-by-cc --smtp-pass --smtp-server --smtp-server-port --smtp-encryption= --smtp-user --subject --suppress-cc= --suppress-from --thread --to @@ -2120,11 +2057,7 @@ _git_status () return ;; --*) - __gitcomp " - --short --branch --porcelain --long --verbose - --untracked-files= --ignore-submodules= --ignored - --column= --no-column - " + __gitcomp_builtin status "--no-column" return ;; esac @@ -2266,14 +2199,7 @@ _git_config () esac case "$cur" in --*) - __gitcomp " - --system --global --local --file= - --list --replace-all - --get --get-all --get-regexp - --add --unset --unset-all - --remove-section --rename-section - --name-only - " + __gitcomp_builtin config return ;; branch.*.*) @@ -2674,7 +2600,7 @@ _git_remote () if [ -z "$subcommand" ]; then case "$cur" in --*) - __gitcomp "--verbose" + __gitcomp_builtin remote ;; *) __gitcomp "$subcommands" @@ -2685,33 +2611,33 @@ _git_remote () case "$subcommand,$cur" in add,--*) - __gitcomp "--track --master --fetch --tags --no-tags --mirror=" + __gitcomp_builtin remote_add "--no-tags" ;; add,*) ;; set-head,--*) - __gitcomp "--auto --delete" + __gitcomp_builtin remote_set-head ;; set-branches,--*) - __gitcomp "--add" + __gitcomp_builtin remote_set-branches ;; set-head,*|set-branches,*) __git_complete_remote_or_refspec ;; update,--*) - __gitcomp "--prune" + __gitcomp_builtin remote_update ;; update,*) __gitcomp "$(__git_get_config_variables "remotes")" ;; set-url,--*) - __gitcomp "--push --add --delete" + __gitcomp_builtin remote_set-url ;; get-url,--*) - __gitcomp "--push --all" + __gitcomp_builtin remote_get-url ;; prune,--*) - __gitcomp "--dry-run" + __gitcomp_builtin remote_prune ;; *) __gitcomp_nl "$(__git_remotes)" @@ -2723,7 +2649,7 @@ _git_replace () { case "$cur" in --*) - __gitcomp "--edit --graft --format= --list --delete" + __gitcomp_builtin replace return ;; esac @@ -2747,26 +2673,26 @@ _git_reset () case "$cur" in --*) - __gitcomp "--merge --mixed --hard --soft --patch --keep" + __gitcomp_builtin reset return ;; esac __git_complete_refs } +__git_revert_inprogress_options="--continue --quit --abort" + _git_revert () { __git_find_repo_path if [ -f "$__git_repo_path"/REVERT_HEAD ]; then - __gitcomp "--continue --quit --abort" + __gitcomp "$__git_revert_inprogress_options" return fi case "$cur" in --*) - __gitcomp " - --edit --mainline --no-edit --no-commit --signoff - --strategy= --strategy-option= - " + __gitcomp_builtin revert "--no-edit" \ + "$__git_revert_inprogress_options" return ;; esac @@ -2777,7 +2703,7 @@ _git_rm () { case "$cur" in --*) - __gitcomp "--cached --dry-run --ignore-unmatch --quiet" + __gitcomp_builtin rm return ;; esac @@ -2835,12 +2761,7 @@ _git_show_branch () { case "$cur" in --*) - __gitcomp " - --all --remotes --topo-order --date-order --current --more= - --list --independent --merge-base --no-name - --color --no-color - --sha1-name --sparse --topics --reflog - " + __gitcomp_builtin show-branch "--no-color" return ;; esac @@ -3047,7 +2968,7 @@ _git_tag () while [ $c -lt $cword ]; do i="${words[c]}" case "$i" in - -d|-v) + -d|--delete|-v|--verify) __gitcomp_direct "$(__git_tags "" "$cur" " ")" return ;; @@ -3073,11 +2994,7 @@ _git_tag () case "$cur" in --*) - __gitcomp " - --list --delete --verify --annotate --message --file - --sign --cleanup --local-user --force --column --sort= - --contains --no-contains --points-at --merged --no-merged --create-reflog - " + __gitcomp_builtin tag ;; esac } @@ -3089,23 +3006,26 @@ _git_whatchanged () _git_worktree () { - local subcommands="add list lock prune unlock" + local subcommands="add list lock move prune remove unlock" local subcommand="$(__git_find_on_cmdline "$subcommands")" if [ -z "$subcommand" ]; then __gitcomp "$subcommands" else case "$subcommand,$cur" in add,--*) - __gitcomp "--detach" + __gitcomp_builtin worktree_add ;; list,--*) - __gitcomp "--porcelain" + __gitcomp_builtin worktree_list ;; lock,--*) - __gitcomp "--reason" + __gitcomp_builtin worktree_lock ;; prune,--*) - __gitcomp "--dry-run --expire --verbose" + __gitcomp_builtin worktree_prune + ;; + remove,--*) + __gitcomp "--force" ;; *) ;; @@ -3113,6 +3033,45 @@ _git_worktree () fi } +__git_complete_common () { + local command="$1" + + case "$cur" in + --*) + __gitcomp_builtin "$command" + ;; + esac +} + +__git_cmds_with_parseopt_helper= +__git_support_parseopt_helper () { + test -n "$__git_cmds_with_parseopt_helper" || + __git_cmds_with_parseopt_helper="$(__git --list-parseopt-builtins)" + + case " $__git_cmds_with_parseopt_helper " in + *" $1 "*) + return 0 + ;; + *) + return 1 + ;; + esac +} + +__git_complete_command () { + local command="$1" + local completion_func="_git_${command//-/_}" + if declare -f $completion_func >/dev/null 2>/dev/null; then + $completion_func + return 0 + elif __git_support_parseopt_helper "$command"; then + __git_complete_common "$command" + return 0 + else + return 1 + fi +} + __git_main () { local i c=1 command __git_dir __git_repo_path @@ -3172,14 +3131,12 @@ __git_main () return fi - local completion_func="_git_${command//-/_}" - declare -f $completion_func >/dev/null 2>/dev/null && $completion_func && return + __git_complete_command "$command" && return local expansion=$(__git_aliased_command "$command") if [ -n "$expansion" ]; then words[1]=$expansion - completion_func="_git_${expansion//-/_}" - declare -f $completion_func >/dev/null 2>/dev/null && $completion_func + __git_complete_command "$expansion" fi } diff --git a/contrib/diff-highlight/DiffHighlight.pm b/contrib/diff-highlight/DiffHighlight.pm index 663992e530..536754583b 100644 --- a/contrib/diff-highlight/DiffHighlight.pm +++ b/contrib/diff-highlight/DiffHighlight.pm @@ -21,37 +21,82 @@ my $RESET = "\x1b[m"; my $COLOR = qr/\x1b\[[0-9;]*m/; my $BORING = qr/$COLOR|\s/; -# The patch portion of git log -p --graph should only ever have preceding | and -# not / or \ as merge history only shows up on the commit line. -my $GRAPH = qr/$COLOR?\|$COLOR?\s+/; - my @removed; my @added; my $in_hunk; +my $graph_indent = 0; our $line_cb = sub { print @_ }; our $flush_cb = sub { local $| = 1 }; -sub handle_line { +# Count the visible width of a string, excluding any terminal color sequences. +sub visible_width { local $_ = shift; + my $ret = 0; + while (length) { + if (s/^$COLOR//) { + # skip colors + } elsif (s/^.//) { + $ret++; + } + } + return $ret; +} + +# Return a substring of $str, omitting $len visible characters from the +# beginning, where terminal color sequences do not count as visible. +sub visible_substr { + my ($str, $len) = @_; + while ($len > 0) { + if ($str =~ s/^$COLOR//) { + next + } + $str =~ s/^.//; + $len--; + } + return $str; +} + +sub handle_line { + my $orig = shift; + local $_ = $orig; + + # match a graph line that begins a commit + if (/^(?:$COLOR?\|$COLOR?[ ])* # zero or more leading "|" with space + $COLOR?\*$COLOR?[ ] # a "*" with its trailing space + (?:$COLOR?\|$COLOR?[ ])* # zero or more trailing "|" + [ ]* # trailing whitespace for merges + /x) { + my $graph_prefix = $&; + + # We must flush before setting graph indent, since the + # new commit may be indented differently from what we + # queued. + flush(); + $graph_indent = visible_width($graph_prefix); + + } elsif ($graph_indent) { + if (length($_) < $graph_indent) { + $graph_indent = 0; + } else { + $_ = visible_substr($_, $graph_indent); + } + } if (!$in_hunk) { - $line_cb->($_); - $in_hunk = /^$GRAPH*$COLOR*\@\@ /; + $line_cb->($orig); + $in_hunk = /^$COLOR*\@\@ /; } - elsif (/^$GRAPH*$COLOR*-/) { - push @removed, $_; + elsif (/^$COLOR*-/) { + push @removed, $orig; } - elsif (/^$GRAPH*$COLOR*\+/) { - push @added, $_; + elsif (/^$COLOR*\+/) { + push @added, $orig; } else { - show_hunk(\@removed, \@added); - @removed = (); - @added = (); - - $line_cb->($_); - $in_hunk = /^$GRAPH*$COLOR*[\@ ]/; + flush(); + $line_cb->($orig); + $in_hunk = /^$COLOR*[\@ ]/; } # Most of the time there is enough output to keep things streaming, @@ -71,6 +116,8 @@ sub flush { # Flush any queued hunk (this can happen when there is no trailing # context in the final diff of the input). show_hunk(\@removed, \@added); + @removed = (); + @added = (); } sub highlight_stdin { @@ -226,8 +273,8 @@ sub is_pair_interesting { my $suffix_a = join('', @$a[($sa+1)..$#$a]); my $suffix_b = join('', @$b[($sb+1)..$#$b]); - return $prefix_a !~ /^$GRAPH*$COLOR*-$BORING*$/ || - $prefix_b !~ /^$GRAPH*$COLOR*\+$BORING*$/ || + return visible_substr($prefix_a, $graph_indent) !~ /^$COLOR*-$BORING*$/ || + visible_substr($prefix_b, $graph_indent) !~ /^$COLOR*\+$BORING*$/ || $suffix_a !~ /^$BORING*$/ || $suffix_b !~ /^$BORING*$/; } diff --git a/contrib/diff-highlight/t/t9400-diff-highlight.sh b/contrib/diff-highlight/t/t9400-diff-highlight.sh index 3b43dbed74..f6f5195d00 100755 --- a/contrib/diff-highlight/t/t9400-diff-highlight.sh +++ b/contrib/diff-highlight/t/t9400-diff-highlight.sh @@ -52,15 +52,17 @@ test_strip_patch_header () { # dh_test_setup_history generates a contrived graph such that we have at least # 1 nesting (E) and 2 nestings (F). # -# A branch -# / -# D---E---F master +# A---B master +# / +# D---E---F branch # # git log --all --graph # * commit -# | A +# | B # | * commit # | | F +# * | commit +# | | A # | * commit # |/ # | E @@ -68,24 +70,30 @@ test_strip_patch_header () { # D # dh_test_setup_history () { - echo "file1" >file1 && - echo "file2" >file2 && - echo "file3" >file3 && - - cat file1 >file && + echo file1 >file && git add file && + test_tick && git commit -m "D" && git checkout -b branch && - cat file2 >file && - git commit -a -m "A" && + echo file2 >file && + test_tick && + git commit -a -m "E" && git checkout master && - cat file2 >file && - git commit -a -m "E" && + echo file2 >file && + test_tick && + git commit -a -m "A" && - cat file3 >file && - git commit -a -m "F" + git checkout branch && + echo file3 >file && + test_tick && + git commit -a -m "F" && + + git checkout master && + echo file3 >file && + test_tick && + git commit -a -m "B" } left_trim () { @@ -246,16 +254,25 @@ test_expect_failure 'diff-highlight treats combining code points as a unit' ' test_expect_success 'diff-highlight works with the --graph option' ' dh_test_setup_history && - # topo-order so that the order of the commits is the same as with --graph + # date-order so that the commits are interleaved for both # trim graph elements so we can do a diff # trim leading space because our trim_graph is not perfect - git log --branches -p --topo-order | + git log --branches -p --date-order | "$DIFF_HIGHLIGHT" | left_trim >graph.exp && - git log --branches -p --graph | + git log --branches -p --date-order --graph | "$DIFF_HIGHLIGHT" | trim_graph | left_trim >graph.act && test_cmp graph.exp graph.act ' +# Just reuse the previous graph test, but with --color. Our trimming +# doesn't know about color, so just sanity check that something got +# highlighted. +test_expect_success 'diff-highlight works with color graph' ' + git log --branches -p --date-order --graph --color | + "$DIFF_HIGHLIGHT" | trim_graph | left_trim >graph && + grep "\[7m" graph +' + # Most combined diffs won't meet diff-highlight's line-number filter. So we # create one here where one side drops a line and the other modifies it. That # should result in a diff like: @@ -293,4 +310,32 @@ test_expect_success 'diff-highlight ignores combined diffs' ' test_cmp expect actual ' +test_expect_success 'diff-highlight handles --graph with leading dash' ' + cat >file <<-\EOF && + before + the old line + -leading dash + EOF + git add file && + git commit -m before && + + sed s/old/new/ <file >file.tmp && + mv file.tmp file && + git add file && + git commit -m after && + + cat >expect <<-EOF && + --- a/file + +++ b/file + @@ -1,3 +1,3 @@ + before + -the ${CW}old${CR} line + +the ${CW}new${CR} line + -leading dash + EOF + git log --graph -p -1 | "$DIFF_HIGHLIGHT" >actual.raw && + trim_graph <actual.raw | sed -n "/^---/,\$p" >actual && + test_cmp expect actual +' + test_done diff --git a/contrib/examples/README b/contrib/examples/README index 6946f3dd2a..18bc60b021 100644 --- a/contrib/examples/README +++ b/contrib/examples/README @@ -1,3 +1,20 @@ -These are original scripted implementations, kept primarily for their -reference value to any aspiring plumbing users who want to learn how -pieces can be fit together. +This directory used to contain scripted implementations of builtins +that have since been rewritten in C. + +They have now been removed, but can be retrieved from an older commit +that removed them from this directory. + +They're interesting for their reference value to any aspiring plumbing +users who want to learn how pieces can be fit together, but in many +cases have drifted enough from the actual implementations Git uses to +be instructive. + +Other things that can be useful: + + * Some commands such as git-gc wrap other commands, and what they're + doing behind the scenes can be seen by running them under + GIT_TRACE=1 + + * Doing `git log` on paths matching '*--helper.c' will show + incremental effort in the direction of moving existing shell + scripts to C. diff --git a/contrib/examples/builtin-fetch--tool.c b/contrib/examples/builtin-fetch--tool.c deleted file mode 100644 index a3eb19de04..0000000000 --- a/contrib/examples/builtin-fetch--tool.c +++ /dev/null @@ -1,575 +0,0 @@ -#include "builtin.h" -#include "cache.h" -#include "refs.h" -#include "commit.h" -#include "sigchain.h" - -static char *get_stdin(void) -{ - struct strbuf buf = STRBUF_INIT; - if (strbuf_read(&buf, 0, 1024) < 0) { - die_errno("error reading standard input"); - } - return strbuf_detach(&buf, NULL); -} - -static void show_new(enum object_type type, unsigned char *sha1_new) -{ - fprintf(stderr, " %s: %s\n", typename(type), - find_unique_abbrev(sha1_new, DEFAULT_ABBREV)); -} - -static int update_ref_env(const char *action, - const char *refname, - unsigned char *sha1, - unsigned char *oldval) -{ - char msg[1024]; - const char *rla = getenv("GIT_REFLOG_ACTION"); - - if (!rla) - rla = "(reflog update)"; - if (snprintf(msg, sizeof(msg), "%s: %s", rla, action) >= sizeof(msg)) - warning("reflog message too long: %.*s...", 50, msg); - return update_ref(msg, refname, sha1, oldval, 0, - UPDATE_REFS_QUIET_ON_ERR); -} - -static int update_local_ref(const char *name, - const char *new_head, - const char *note, - int verbose, int force) -{ - unsigned char sha1_old[20], sha1_new[20]; - char oldh[41], newh[41]; - struct commit *current, *updated; - enum object_type type; - - if (get_sha1_hex(new_head, sha1_new)) - die("malformed object name %s", new_head); - - type = sha1_object_info(sha1_new, NULL); - if (type < 0) - die("object %s not found", new_head); - - if (!*name) { - /* Not storing */ - if (verbose) { - fprintf(stderr, "* fetched %s\n", note); - show_new(type, sha1_new); - } - return 0; - } - - if (get_sha1(name, sha1_old)) { - const char *msg; - just_store: - /* new ref */ - if (!strncmp(name, "refs/tags/", 10)) - msg = "storing tag"; - else - msg = "storing head"; - fprintf(stderr, "* %s: storing %s\n", - name, note); - show_new(type, sha1_new); - return update_ref_env(msg, name, sha1_new, NULL); - } - - if (!hashcmp(sha1_old, sha1_new)) { - if (verbose) { - fprintf(stderr, "* %s: same as %s\n", name, note); - show_new(type, sha1_new); - } - return 0; - } - - if (!strncmp(name, "refs/tags/", 10)) { - fprintf(stderr, "* %s: updating with %s\n", name, note); - show_new(type, sha1_new); - return update_ref_env("updating tag", name, sha1_new, NULL); - } - - current = lookup_commit_reference(sha1_old); - updated = lookup_commit_reference(sha1_new); - if (!current || !updated) - goto just_store; - - strcpy(oldh, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); - strcpy(newh, find_unique_abbrev(sha1_new, DEFAULT_ABBREV)); - - if (in_merge_bases(current, updated)) { - fprintf(stderr, "* %s: fast-forward to %s\n", - name, note); - fprintf(stderr, " old..new: %s..%s\n", oldh, newh); - return update_ref_env("fast-forward", name, sha1_new, sha1_old); - } - if (!force) { - fprintf(stderr, - "* %s: not updating to non-fast-forward %s\n", - name, note); - fprintf(stderr, - " old...new: %s...%s\n", oldh, newh); - return 1; - } - fprintf(stderr, - "* %s: forcing update to non-fast-forward %s\n", - name, note); - fprintf(stderr, " old...new: %s...%s\n", oldh, newh); - return update_ref_env("forced-update", name, sha1_new, sha1_old); -} - -static int append_fetch_head(FILE *fp, - const char *head, const char *remote, - const char *remote_name, const char *remote_nick, - const char *local_name, int not_for_merge, - int verbose, int force) -{ - struct commit *commit; - int remote_len, i, note_len; - unsigned char sha1[20]; - char note[1024]; - const char *what, *kind; - - if (get_sha1(head, sha1)) - return error("Not a valid object name: %s", head); - commit = lookup_commit_reference_gently(sha1, 1); - if (!commit) - not_for_merge = 1; - - if (!strcmp(remote_name, "HEAD")) { - kind = ""; - what = ""; - } - else if (!strncmp(remote_name, "refs/heads/", 11)) { - kind = "branch"; - what = remote_name + 11; - } - else if (!strncmp(remote_name, "refs/tags/", 10)) { - kind = "tag"; - what = remote_name + 10; - } - else if (!strncmp(remote_name, "refs/remotes/", 13)) { - kind = "remote-tracking branch"; - what = remote_name + 13; - } - else { - kind = ""; - what = remote_name; - } - - remote_len = strlen(remote); - for (i = remote_len - 1; remote[i] == '/' && 0 <= i; i--) - ; - remote_len = i + 1; - if (4 < i && !strncmp(".git", remote + i - 3, 4)) - remote_len = i - 3; - - note_len = 0; - if (*what) { - if (*kind) - note_len += sprintf(note + note_len, "%s ", kind); - note_len += sprintf(note + note_len, "'%s' of ", what); - } - note_len += sprintf(note + note_len, "%.*s", remote_len, remote); - fprintf(fp, "%s\t%s\t%s\n", - sha1_to_hex(commit ? commit->object.sha1 : sha1), - not_for_merge ? "not-for-merge" : "", - note); - return update_local_ref(local_name, head, note, verbose, force); -} - -static char *keep; -static void remove_keep(void) -{ - if (keep && *keep) - unlink(keep); -} - -static void remove_keep_on_signal(int signo) -{ - remove_keep(); - sigchain_pop(signo); - raise(signo); -} - -static char *find_local_name(const char *remote_name, const char *refs, - int *force_p, int *not_for_merge_p) -{ - const char *ref = refs; - int len = strlen(remote_name); - - while (ref) { - const char *next; - int single_force, not_for_merge; - - while (*ref == '\n') - ref++; - if (!*ref) - break; - next = strchr(ref, '\n'); - - single_force = not_for_merge = 0; - if (*ref == '+') { - single_force = 1; - ref++; - } - if (*ref == '.') { - not_for_merge = 1; - ref++; - if (*ref == '+') { - single_force = 1; - ref++; - } - } - if (!strncmp(remote_name, ref, len) && ref[len] == ':') { - const char *local_part = ref + len + 1; - int retlen; - - if (!next) - retlen = strlen(local_part); - else - retlen = next - local_part; - *force_p = single_force; - *not_for_merge_p = not_for_merge; - return xmemdupz(local_part, retlen); - } - ref = next; - } - return NULL; -} - -static int fetch_native_store(FILE *fp, - const char *remote, - const char *remote_nick, - const char *refs, - int verbose, int force) -{ - char buffer[1024]; - int err = 0; - - sigchain_push_common(remove_keep_on_signal); - atexit(remove_keep); - - while (fgets(buffer, sizeof(buffer), stdin)) { - int len; - char *cp; - char *local_name; - int single_force, not_for_merge; - - for (cp = buffer; *cp && !isspace(*cp); cp++) - ; - if (*cp) - *cp++ = 0; - len = strlen(cp); - if (len && cp[len-1] == '\n') - cp[--len] = 0; - if (!strcmp(buffer, "failed")) - die("Fetch failure: %s", remote); - if (!strcmp(buffer, "pack")) - continue; - if (!strcmp(buffer, "keep")) { - char *od = get_object_directory(); - int len = strlen(od) + strlen(cp) + 50; - keep = xmalloc(len); - sprintf(keep, "%s/pack/pack-%s.keep", od, cp); - continue; - } - - local_name = find_local_name(cp, refs, - &single_force, ¬_for_merge); - if (!local_name) - continue; - err |= append_fetch_head(fp, - buffer, remote, cp, remote_nick, - local_name, not_for_merge, - verbose, force || single_force); - } - return err; -} - -static int parse_reflist(const char *reflist) -{ - const char *ref; - - printf("refs='"); - for (ref = reflist; ref; ) { - const char *next; - while (*ref && isspace(*ref)) - ref++; - if (!*ref) - break; - for (next = ref; *next && !isspace(*next); next++) - ; - printf("\n%.*s", (int)(next - ref), ref); - ref = next; - } - printf("'\n"); - - printf("rref='"); - for (ref = reflist; ref; ) { - const char *next, *colon; - while (*ref && isspace(*ref)) - ref++; - if (!*ref) - break; - for (next = ref; *next && !isspace(*next); next++) - ; - if (*ref == '.') - ref++; - if (*ref == '+') - ref++; - colon = strchr(ref, ':'); - putchar('\n'); - printf("%.*s", (int)((colon ? colon : next) - ref), ref); - ref = next; - } - printf("'\n"); - return 0; -} - -static int expand_refs_wildcard(const char *ls_remote_result, int numrefs, - const char **refs) -{ - int i, matchlen, replacelen; - int found_one = 0; - const char *remote = *refs++; - numrefs--; - - if (numrefs == 0) { - fprintf(stderr, "Nothing specified for fetching with remote.%s.fetch\n", - remote); - printf("empty\n"); - } - - for (i = 0; i < numrefs; i++) { - const char *ref = refs[i]; - const char *lref = ref; - const char *colon; - const char *tail; - const char *ls; - const char *next; - - if (*lref == '+') - lref++; - colon = strchr(lref, ':'); - tail = lref + strlen(lref); - if (!(colon && - 2 < colon - lref && - colon[-1] == '*' && - colon[-2] == '/' && - 2 < tail - (colon + 1) && - tail[-1] == '*' && - tail[-2] == '/')) { - /* not a glob */ - if (!found_one++) - printf("explicit\n"); - printf("%s\n", ref); - continue; - } - - /* glob */ - if (!found_one++) - printf("glob\n"); - - /* lref to colon-2 is remote hierarchy name; - * colon+1 to tail-2 is local. - */ - matchlen = (colon-1) - lref; - replacelen = (tail-1) - (colon+1); - for (ls = ls_remote_result; ls; ls = next) { - const char *eol; - unsigned char sha1[20]; - int namelen; - - while (*ls && isspace(*ls)) - ls++; - next = strchr(ls, '\n'); - eol = !next ? (ls + strlen(ls)) : next; - if (!memcmp("^{}", eol-3, 3)) - continue; - if (eol - ls < 40) - continue; - if (get_sha1_hex(ls, sha1)) - continue; - ls += 40; - while (ls < eol && isspace(*ls)) - ls++; - /* ls to next (or eol) is the name. - * is it identical to lref to colon-2? - */ - if ((eol - ls) <= matchlen || - strncmp(ls, lref, matchlen)) - continue; - - /* Yes, it is a match */ - namelen = eol - ls; - if (lref != ref) - putchar('+'); - printf("%.*s:%.*s%.*s\n", - namelen, ls, - replacelen, colon + 1, - namelen - matchlen, ls + matchlen); - } - } - return 0; -} - -static int pick_rref(int sha1_only, const char *rref, const char *ls_remote_result) -{ - int err = 0; - int lrr_count = lrr_count, i, pass; - const char *cp; - struct lrr { - const char *line; - const char *name; - int namelen; - int shown; - } *lrr_list = lrr_list; - - for (pass = 0; pass < 2; pass++) { - /* pass 0 counts and allocates, pass 1 fills... */ - cp = ls_remote_result; - i = 0; - while (1) { - const char *np; - while (*cp && isspace(*cp)) - cp++; - if (!*cp) - break; - np = strchrnul(cp, '\n'); - if (pass) { - lrr_list[i].line = cp; - lrr_list[i].name = cp + 41; - lrr_list[i].namelen = np - (cp + 41); - } - i++; - cp = np; - } - if (!pass) { - lrr_count = i; - lrr_list = xcalloc(lrr_count, sizeof(*lrr_list)); - } - } - - while (1) { - const char *next; - int rreflen; - int i; - - while (*rref && isspace(*rref)) - rref++; - if (!*rref) - break; - next = strchrnul(rref, '\n'); - rreflen = next - rref; - - for (i = 0; i < lrr_count; i++) { - struct lrr *lrr = &(lrr_list[i]); - - if (rreflen == lrr->namelen && - !memcmp(lrr->name, rref, rreflen)) { - if (!lrr->shown) - printf("%.*s\n", - sha1_only ? 40 : lrr->namelen + 41, - lrr->line); - lrr->shown = 1; - break; - } - } - if (lrr_count <= i) { - error("pick-rref: %.*s not found", rreflen, rref); - err = 1; - } - rref = next; - } - free(lrr_list); - return err; -} - -int cmd_fetch__tool(int argc, const char **argv, const char *prefix) -{ - int verbose = 0; - int force = 0; - int sopt = 0; - - while (1 < argc) { - const char *arg = argv[1]; - if (!strcmp("-v", arg)) - verbose = 1; - else if (!strcmp("-f", arg)) - force = 1; - else if (!strcmp("-s", arg)) - sopt = 1; - else - break; - argc--; - argv++; - } - - if (argc <= 1) - return error("Missing subcommand"); - - if (!strcmp("append-fetch-head", argv[1])) { - int result; - FILE *fp; - char *filename; - - if (argc != 8) - return error("append-fetch-head takes 6 args"); - filename = git_path_fetch_head(); - fp = fopen(filename, "a"); - if (!fp) - return error("cannot open %s: %s", filename, strerror(errno)); - result = append_fetch_head(fp, argv[2], argv[3], - argv[4], argv[5], - argv[6], !!argv[7][0], - verbose, force); - fclose(fp); - return result; - } - if (!strcmp("native-store", argv[1])) { - int result; - FILE *fp; - char *filename; - - if (argc != 5) - return error("fetch-native-store takes 3 args"); - filename = git_path_fetch_head(); - fp = fopen(filename, "a"); - if (!fp) - return error("cannot open %s: %s", filename, strerror(errno)); - result = fetch_native_store(fp, argv[2], argv[3], argv[4], - verbose, force); - fclose(fp); - return result; - } - if (!strcmp("parse-reflist", argv[1])) { - const char *reflist; - if (argc != 3) - return error("parse-reflist takes 1 arg"); - reflist = argv[2]; - if (!strcmp(reflist, "-")) - reflist = get_stdin(); - return parse_reflist(reflist); - } - if (!strcmp("pick-rref", argv[1])) { - const char *ls_remote_result; - if (argc != 4) - return error("pick-rref takes 2 args"); - ls_remote_result = argv[3]; - if (!strcmp(ls_remote_result, "-")) - ls_remote_result = get_stdin(); - return pick_rref(sopt, argv[2], ls_remote_result); - } - if (!strcmp("expand-refs-wildcard", argv[1])) { - const char *reflist; - if (argc < 4) - return error("expand-refs-wildcard takes at least 2 args"); - reflist = argv[2]; - if (!strcmp(reflist, "-")) - reflist = get_stdin(); - return expand_refs_wildcard(reflist, argc - 3, argv + 3); - } - - return error("Unknown subcommand: %s", argv[1]); -} diff --git a/contrib/examples/git-am.sh b/contrib/examples/git-am.sh deleted file mode 100755 index dd539f1a8a..0000000000 --- a/contrib/examples/git-am.sh +++ /dev/null @@ -1,975 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005, 2006 Junio C Hamano - -SUBDIRECTORY_OK=Yes -OPTIONS_KEEPDASHDASH= -OPTIONS_STUCKLONG=t -OPTIONS_SPEC="\ -git am [options] [(<mbox>|<Maildir>)...] -git am [options] (--continue | --skip | --abort) --- -i,interactive run interactively -b,binary* (historical option -- no-op) -3,3way allow fall back on 3way merging if needed -q,quiet be quiet -s,signoff add a Signed-off-by line to the commit message -u,utf8 recode into utf8 (default) -k,keep pass -k flag to git-mailinfo -keep-non-patch pass -b flag to git-mailinfo -m,message-id pass -m flag to git-mailinfo -keep-cr pass --keep-cr flag to git-mailsplit for mbox format -no-keep-cr do not pass --keep-cr flag to git-mailsplit independent of am.keepcr -c,scissors strip everything before a scissors line -whitespace= pass it through git-apply -ignore-space-change pass it through git-apply -ignore-whitespace pass it through git-apply -directory= pass it through git-apply -exclude= pass it through git-apply -include= pass it through git-apply -C= pass it through git-apply -p= pass it through git-apply -patch-format= format the patch(es) are in -reject pass it through git-apply -resolvemsg= override error message when patch failure occurs -continue continue applying patches after resolving a conflict -r,resolved synonyms for --continue -skip skip the current patch -abort restore the original branch and abort the patching operation. -committer-date-is-author-date lie about committer date -ignore-date use current timestamp for author date -rerere-autoupdate update the index with reused conflict resolution if possible -S,gpg-sign? GPG-sign commits -rebasing* (internal use for git-rebase)" - -. git-sh-setup -. git-sh-i18n -prefix=$(git rev-parse --show-prefix) -set_reflog_action am -require_work_tree -cd_to_toplevel - -git var GIT_COMMITTER_IDENT >/dev/null || - die "$(gettext "You need to set your committer info first")" - -if git rev-parse --verify -q HEAD >/dev/null -then - HAS_HEAD=yes -else - HAS_HEAD= -fi - -cmdline="git am" -if test '' != "$interactive" -then - cmdline="$cmdline -i" -fi -if test '' != "$threeway" -then - cmdline="$cmdline -3" -fi - -empty_tree=4b825dc642cb6eb9a060e54bf8d69288fbee4904 - -sq () { - git rev-parse --sq-quote "$@" -} - -stop_here () { - echo "$1" >"$dotest/next" - git rev-parse --verify -q HEAD >"$dotest/abort-safety" - exit 1 -} - -safe_to_abort () { - if test -f "$dotest/dirtyindex" - then - return 1 - fi - - if ! test -f "$dotest/abort-safety" - then - return 0 - fi - - abort_safety=$(cat "$dotest/abort-safety") - if test "z$(git rev-parse --verify -q HEAD)" = "z$abort_safety" - then - return 0 - fi - gettextln "You seem to have moved HEAD since the last 'am' failure. -Not rewinding to ORIG_HEAD" >&2 - return 1 -} - -stop_here_user_resolve () { - if [ -n "$resolvemsg" ]; then - printf '%s\n' "$resolvemsg" - stop_here $1 - fi - eval_gettextln "When you have resolved this problem, run \"\$cmdline --continue\". -If you prefer to skip this patch, run \"\$cmdline --skip\" instead. -To restore the original branch and stop patching, run \"\$cmdline --abort\"." - - stop_here $1 -} - -go_next () { - rm -f "$dotest/$msgnum" "$dotest/msg" "$dotest/msg-clean" \ - "$dotest/patch" "$dotest/info" - echo "$next" >"$dotest/next" - this=$next -} - -cannot_fallback () { - echo "$1" - gettextln "Cannot fall back to three-way merge." - exit 1 -} - -fall_back_3way () { - O_OBJECT=$(cd "$GIT_OBJECT_DIRECTORY" && pwd) - - rm -fr "$dotest"/patch-merge-* - mkdir "$dotest/patch-merge-tmp-dir" - - # First see if the patch records the index info that we can use. - cmd="git apply $git_apply_opt --build-fake-ancestor" && - cmd="$cmd "'"$dotest/patch-merge-tmp-index" "$dotest/patch"' && - eval "$cmd" && - GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \ - git write-tree >"$dotest/patch-merge-base+" || - cannot_fallback "$(gettext "Repository lacks necessary blobs to fall back on 3-way merge.")" - - say "$(gettext "Using index info to reconstruct a base tree...")" - - cmd='GIT_INDEX_FILE="$dotest/patch-merge-tmp-index"' - - if test -z "$GIT_QUIET" - then - eval "$cmd git diff-index --cached --diff-filter=AM --name-status HEAD" - fi - - cmd="$cmd git apply --cached $git_apply_opt"' <"$dotest/patch"' - if eval "$cmd" - then - mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base" - mv "$dotest/patch-merge-tmp-index" "$dotest/patch-merge-index" - else - cannot_fallback "$(gettext "Did you hand edit your patch? -It does not apply to blobs recorded in its index.")" - fi - - test -f "$dotest/patch-merge-index" && - his_tree=$(GIT_INDEX_FILE="$dotest/patch-merge-index" git write-tree) && - orig_tree=$(cat "$dotest/patch-merge-base") && - rm -fr "$dotest"/patch-merge-* || exit 1 - - say "$(gettext "Falling back to patching base and 3-way merge...")" - - # This is not so wrong. Depending on which base we picked, - # orig_tree may be wildly different from ours, but his_tree - # has the same set of wildly different changes in parts the - # patch did not touch, so recursive ends up canceling them, - # saying that we reverted all those changes. - - eval GITHEAD_$his_tree='"$FIRSTLINE"' - export GITHEAD_$his_tree - if test -n "$GIT_QUIET" - then - GIT_MERGE_VERBOSITY=0 && export GIT_MERGE_VERBOSITY - fi - our_tree=$(git rev-parse --verify -q HEAD || echo $empty_tree) - git-merge-recursive $orig_tree -- $our_tree $his_tree || { - git rerere $allow_rerere_autoupdate - die "$(gettext "Failed to merge in the changes.")" - } - unset GITHEAD_$his_tree -} - -clean_abort () { - test $# = 0 || echo >&2 "$@" - rm -fr "$dotest" - exit 1 -} - -patch_format= - -check_patch_format () { - # early return if patch_format was set from the command line - if test -n "$patch_format" - then - return 0 - fi - - # we default to mbox format if input is from stdin and for - # directories - if test $# = 0 || test "x$1" = "x-" || test -d "$1" - then - patch_format=mbox - return 0 - fi - - # otherwise, check the first few non-blank lines of the first - # patch to try to detect its format - { - # Start from first line containing non-whitespace - l1= - while test -z "$l1" - do - read l1 || break - done - read l2 - read l3 - case "$l1" in - "From "* | "From: "*) - patch_format=mbox - ;; - '# This series applies on GIT commit'*) - patch_format=stgit-series - ;; - "# HG changeset patch") - patch_format=hg - ;; - *) - # if the second line is empty and the third is - # a From, Author or Date entry, this is very - # likely an StGIT patch - case "$l2,$l3" in - ,"From: "* | ,"Author: "* | ,"Date: "*) - patch_format=stgit - ;; - *) - ;; - esac - ;; - esac - if test -z "$patch_format" && - test -n "$l1" && - test -n "$l2" && - test -n "$l3" - then - # This begins with three non-empty lines. Is this a - # piece of e-mail a-la RFC2822? Grab all the headers, - # discarding the indented remainder of folded lines, - # and see if it looks like that they all begin with the - # header field names... - tr -d '\015' <"$1" | - sed -n -e '/^$/q' -e '/^[ ]/d' -e p | - sane_egrep -v '^[!-9;-~]+:' >/dev/null || - patch_format=mbox - fi - } < "$1" || clean_abort -} - -split_patches () { - case "$patch_format" in - mbox) - if test t = "$keepcr" - then - keep_cr=--keep-cr - else - keep_cr= - fi - git mailsplit -d"$prec" -o"$dotest" -b $keep_cr -- "$@" > "$dotest/last" || - clean_abort - ;; - stgit-series) - if test $# -ne 1 - then - clean_abort "$(gettext "Only one StGIT patch series can be applied at once")" - fi - series_dir=$(dirname "$1") - series_file="$1" - shift - { - set x - while read filename - do - set "$@" "$series_dir/$filename" - done - # remove the safety x - shift - # remove the arg coming from the first-line comment - shift - } < "$series_file" || clean_abort - # set the patch format appropriately - patch_format=stgit - # now handle the actual StGIT patches - split_patches "$@" - ;; - stgit) - this=0 - test 0 -eq "$#" && set -- - - for stgit in "$@" - do - this=$(expr "$this" + 1) - msgnum=$(printf "%0${prec}d" $this) - # Perl version of StGIT parse_patch. The first nonemptyline - # not starting with Author, From or Date is the - # subject, and the body starts with the next nonempty - # line not starting with Author, From or Date - @@PERL@@ -ne 'BEGIN { $subject = 0 } - if ($subject > 1) { print ; } - elsif (/^\s+$/) { next ; } - elsif (/^Author:/) { s/Author/From/ ; print ;} - elsif (/^(From|Date)/) { print ; } - elsif ($subject) { - $subject = 2 ; - print "\n" ; - print ; - } else { - print "Subject: ", $_ ; - $subject = 1; - } - ' -- "$stgit" >"$dotest/$msgnum" || clean_abort - done - echo "$this" > "$dotest/last" - this= - msgnum= - ;; - hg) - this=0 - test 0 -eq "$#" && set -- - - for hg in "$@" - do - this=$(( $this + 1 )) - msgnum=$(printf "%0${prec}d" $this) - # hg stores changeset metadata in #-commented lines preceding - # the commit message and diff(s). The only metadata we care about - # are the User and Date (Node ID and Parent are hashes which are - # only relevant to the hg repository and thus not useful to us) - # Since we cannot guarantee that the commit message is in - # git-friendly format, we put no Subject: line and just consume - # all of the message as the body - LANG=C LC_ALL=C @@PERL@@ -M'POSIX qw(strftime)' -ne 'BEGIN { $subject = 0 } - if ($subject) { print ; } - elsif (/^\# User /) { s/\# User/From:/ ; print ; } - elsif (/^\# Date /) { - my ($hashsign, $str, $time, $tz) = split ; - $tz_str = sprintf "%+05d", (0-$tz)/36; - print "Date: " . - strftime("%a, %d %b %Y %H:%M:%S ", - gmtime($time-$tz)) - . "$tz_str\n"; - } elsif (/^\# /) { next ; } - else { - print "\n", $_ ; - $subject = 1; - } - ' -- "$hg" >"$dotest/$msgnum" || clean_abort - done - echo "$this" >"$dotest/last" - this= - msgnum= - ;; - *) - if test -n "$patch_format" - then - clean_abort "$(eval_gettext "Patch format \$patch_format is not supported.")" - else - clean_abort "$(gettext "Patch format detection failed.")" - fi - ;; - esac -} - -prec=4 -dotest="$GIT_DIR/rebase-apply" -sign= utf8=t keep= keepcr= skip= interactive= resolved= rebasing= abort= -messageid= resolvemsg= resume= scissors= no_inbody_headers= -git_apply_opt= -committer_date_is_author_date= -ignore_date= -allow_rerere_autoupdate= -gpg_sign_opt= -threeway= - -if test "$(git config --bool --get am.messageid)" = true -then - messageid=t -fi - -if test "$(git config --bool --get am.keepcr)" = true -then - keepcr=t -fi - -while test $# != 0 -do - case "$1" in - -i|--interactive) - interactive=t ;; - -b|--binary) - gettextln >&2 "The -b/--binary option has been a no-op for long time, and -it will be removed. Please do not use it anymore." - ;; - -3|--3way) - threeway=t ;; - -s|--signoff) - sign=t ;; - -u|--utf8) - utf8=t ;; # this is now default - --no-utf8) - utf8= ;; - -m|--message-id) - messageid=t ;; - --no-message-id) - messageid=f ;; - -k|--keep) - keep=t ;; - --keep-non-patch) - keep=b ;; - -c|--scissors) - scissors=t ;; - --no-scissors) - scissors=f ;; - -r|--resolved|--continue) - resolved=t ;; - --skip) - skip=t ;; - --abort) - abort=t ;; - --rebasing) - rebasing=t threeway=t ;; - --resolvemsg=*) - resolvemsg="${1#--resolvemsg=}" ;; - --whitespace=*|--directory=*|--exclude=*|--include=*) - git_apply_opt="$git_apply_opt $(sq "$1")" ;; - -C*|-p*) - git_apply_opt="$git_apply_opt $(sq "$1")" ;; - --patch-format=*) - patch_format="${1#--patch-format=}" ;; - --reject|--ignore-whitespace|--ignore-space-change) - git_apply_opt="$git_apply_opt $1" ;; - --committer-date-is-author-date) - committer_date_is_author_date=t ;; - --ignore-date) - ignore_date=t ;; - --rerere-autoupdate|--no-rerere-autoupdate) - allow_rerere_autoupdate="$1" ;; - -q|--quiet) - GIT_QUIET=t ;; - --keep-cr) - keepcr=t ;; - --no-keep-cr) - keepcr=f ;; - --gpg-sign) - gpg_sign_opt=-S ;; - --gpg-sign=*) - gpg_sign_opt="-S${1#--gpg-sign=}" ;; - --) - shift; break ;; - *) - usage ;; - esac - shift -done - -# If the dotest directory exists, but we have finished applying all the -# patches in them, clear it out. -if test -d "$dotest" && - test -f "$dotest/last" && - test -f "$dotest/next" && - last=$(cat "$dotest/last") && - next=$(cat "$dotest/next") && - test $# != 0 && - test "$next" -gt "$last" -then - rm -fr "$dotest" -fi - -if test -d "$dotest" && test -f "$dotest/last" && test -f "$dotest/next" -then - case "$#,$skip$resolved$abort" in - 0,*t*) - # Explicit resume command and we do not have file, so - # we are happy. - : ;; - 0,) - # No file input but without resume parameters; catch - # user error to feed us a patch from standard input - # when there is already $dotest. This is somewhat - # unreliable -- stdin could be /dev/null for example - # and the caller did not intend to feed us a patch but - # wanted to continue unattended. - test -t 0 - ;; - *) - false - ;; - esac || - die "$(eval_gettext "previous rebase directory \$dotest still exists but mbox given.")" - resume=yes - - case "$skip,$abort" in - t,t) - die "$(gettext "Please make up your mind. --skip or --abort?")" - ;; - t,) - git rerere clear - head_tree=$(git rev-parse --verify -q HEAD || echo $empty_tree) && - git read-tree --reset -u $head_tree $head_tree && - index_tree=$(git write-tree) && - git read-tree -m -u $index_tree $head_tree - git read-tree -m $head_tree - ;; - ,t) - if test -f "$dotest/rebasing" - then - exec git rebase --abort - fi - git rerere clear - if safe_to_abort - then - head_tree=$(git rev-parse --verify -q HEAD || echo $empty_tree) && - git read-tree --reset -u $head_tree $head_tree && - index_tree=$(git write-tree) && - orig_head=$(git rev-parse --verify -q ORIG_HEAD || echo $empty_tree) && - git read-tree -m -u $index_tree $orig_head - if git rev-parse --verify -q ORIG_HEAD >/dev/null 2>&1 - then - git reset ORIG_HEAD - else - git read-tree $empty_tree - curr_branch=$(git symbolic-ref HEAD 2>/dev/null) && - git update-ref -d $curr_branch - fi - fi - rm -fr "$dotest" - exit ;; - esac - rm -f "$dotest/dirtyindex" -else - # Possible stray $dotest directory in the independent-run - # case; in the --rebasing case, it is upto the caller - # (git-rebase--am) to take care of stray directories. - if test -d "$dotest" && test -z "$rebasing" - then - case "$skip,$resolved,$abort" in - ,,t) - rm -fr "$dotest" - exit 0 - ;; - *) - die "$(eval_gettext "Stray \$dotest directory found. -Use \"git am --abort\" to remove it.")" - ;; - esac - fi - - # Make sure we are not given --skip, --continue, or --abort - test "$skip$resolved$abort" = "" || - die "$(gettext "Resolve operation not in progress, we are not resuming.")" - - # Start afresh. - mkdir -p "$dotest" || exit - - if test -n "$prefix" && test $# != 0 - then - first=t - for arg - do - test -n "$first" && { - set x - first= - } - if is_absolute_path "$arg" - then - set "$@" "$arg" - else - set "$@" "$prefix$arg" - fi - done - shift - fi - - check_patch_format "$@" - - split_patches "$@" - - # -i can and must be given when resuming; everything - # else is kept - echo " $git_apply_opt" >"$dotest/apply-opt" - echo "$threeway" >"$dotest/threeway" - echo "$sign" >"$dotest/sign" - echo "$utf8" >"$dotest/utf8" - echo "$keep" >"$dotest/keep" - echo "$messageid" >"$dotest/messageid" - echo "$scissors" >"$dotest/scissors" - echo "$no_inbody_headers" >"$dotest/no_inbody_headers" - echo "$GIT_QUIET" >"$dotest/quiet" - echo 1 >"$dotest/next" - if test -n "$rebasing" - then - : >"$dotest/rebasing" - else - : >"$dotest/applying" - if test -n "$HAS_HEAD" - then - git update-ref ORIG_HEAD HEAD - else - git update-ref -d ORIG_HEAD >/dev/null 2>&1 - fi - fi -fi - -git update-index -q --refresh - -case "$resolved" in -'') - case "$HAS_HEAD" in - '') - files=$(git ls-files) ;; - ?*) - files=$(git diff-index --cached --name-only HEAD --) ;; - esac || exit - if test "$files" - then - test -n "$HAS_HEAD" && : >"$dotest/dirtyindex" - die "$(eval_gettext "Dirty index: cannot apply patches (dirty: \$files)")" - fi -esac - -# Now, decide what command line options we will give to the git -# commands we invoke, based on the result of parsing command line -# options and previous invocation state stored in $dotest/ files. - -if test "$(cat "$dotest/utf8")" = t -then - utf8=-u -else - utf8=-n -fi -keep=$(cat "$dotest/keep") -case "$keep" in -t) - keep=-k ;; -b) - keep=-b ;; -*) - keep= ;; -esac -case "$(cat "$dotest/messageid")" in -t) - messageid=-m ;; -f) - messageid= ;; -esac -case "$(cat "$dotest/scissors")" in -t) - scissors=--scissors ;; -f) - scissors=--no-scissors ;; -esac -if test "$(cat "$dotest/no_inbody_headers")" = t -then - no_inbody_headers=--no-inbody-headers -else - no_inbody_headers= -fi -if test "$(cat "$dotest/quiet")" = t -then - GIT_QUIET=t -fi -if test "$(cat "$dotest/threeway")" = t -then - threeway=t -fi -git_apply_opt=$(cat "$dotest/apply-opt") -if test "$(cat "$dotest/sign")" = t -then - SIGNOFF=$(git var GIT_COMMITTER_IDENT | sed -e ' - s/>.*/>/ - s/^/Signed-off-by: /' - ) -else - SIGNOFF= -fi - -last=$(cat "$dotest/last") -this=$(cat "$dotest/next") -if test "$skip" = t -then - this=$(expr "$this" + 1) - resume= -fi - -while test "$this" -le "$last" -do - msgnum=$(printf "%0${prec}d" $this) - next=$(expr "$this" + 1) - test -f "$dotest/$msgnum" || { - resume= - go_next - continue - } - - # If we are not resuming, parse and extract the patch information - # into separate files: - # - info records the authorship and title - # - msg is the rest of commit log message - # - patch is the patch body. - # - # When we are resuming, these files are either already prepared - # by the user, or the user can tell us to do so by --continue flag. - case "$resume" in - '') - if test -f "$dotest/rebasing" - then - commit=$(sed -e 's/^From \([0-9a-f]*\) .*/\1/' \ - -e q "$dotest/$msgnum") && - test "$(git cat-file -t "$commit")" = commit || - stop_here $this - git cat-file commit "$commit" | - sed -e '1,/^$/d' >"$dotest/msg-clean" - echo "$commit" >"$dotest/original-commit" - get_author_ident_from_commit "$commit" >"$dotest/author-script" - git diff-tree --root --binary --full-index "$commit" >"$dotest/patch" - else - git mailinfo $keep $no_inbody_headers $messageid $scissors $utf8 "$dotest/msg" "$dotest/patch" \ - <"$dotest/$msgnum" >"$dotest/info" || - stop_here $this - - # skip pine's internal folder data - sane_grep '^Author: Mail System Internal Data$' \ - <"$dotest"/info >/dev/null && - go_next && continue - - test -s "$dotest/patch" || { - eval_gettextln "Patch is empty. Was it split wrong? -If you would prefer to skip this patch, instead run \"\$cmdline --skip\". -To restore the original branch and stop patching run \"\$cmdline --abort\"." - stop_here $this - } - rm -f "$dotest/original-commit" "$dotest/author-script" - { - sed -n '/^Subject/ s/Subject: //p' "$dotest/info" - echo - cat "$dotest/msg" - } | - git stripspace > "$dotest/msg-clean" - fi - ;; - esac - - if test -f "$dotest/author-script" - then - eval $(cat "$dotest/author-script") - else - GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$dotest/info")" - GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$dotest/info")" - GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$dotest/info")" - fi - - if test -z "$GIT_AUTHOR_EMAIL" - then - gettextln "Patch does not have a valid e-mail address." - stop_here $this - fi - - export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE - - case "$resume" in - '') - if test '' != "$SIGNOFF" - then - LAST_SIGNED_OFF_BY=$( - sed -ne '/^Signed-off-by: /p' \ - "$dotest/msg-clean" | - sed -ne '$p' - ) - ADD_SIGNOFF=$( - test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || { - test '' = "$LAST_SIGNED_OFF_BY" && echo - echo "$SIGNOFF" - }) - else - ADD_SIGNOFF= - fi - { - if test -s "$dotest/msg-clean" - then - cat "$dotest/msg-clean" - fi - if test '' != "$ADD_SIGNOFF" - then - echo "$ADD_SIGNOFF" - fi - } >"$dotest/final-commit" - ;; - *) - case "$resolved$interactive" in - tt) - # This is used only for interactive view option. - git diff-index -p --cached HEAD -- >"$dotest/patch" - ;; - esac - esac - - resume= - if test "$interactive" = t - then - test -t 0 || - die "$(gettext "cannot be interactive without stdin connected to a terminal.")" - action=again - while test "$action" = again - do - gettextln "Commit Body is:" - echo "--------------------------" - cat "$dotest/final-commit" - echo "--------------------------" - # TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a] - # in your translation. The program will only accept English - # input at this point. - gettext "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " - read reply - case "$reply" in - [yY]*) action=yes ;; - [aA]*) action=yes interactive= ;; - [nN]*) action=skip ;; - [eE]*) git_editor "$dotest/final-commit" - action=again ;; - [vV]*) action=again - git_pager "$dotest/patch" ;; - *) action=again ;; - esac - done - else - action=yes - fi - - if test $action = skip - then - go_next - continue - fi - - hook="$(git rev-parse --git-path hooks/applypatch-msg)" - if test -x "$hook" - then - "$hook" "$dotest/final-commit" || stop_here $this - fi - - if test -f "$dotest/final-commit" - then - FIRSTLINE=$(sed 1q "$dotest/final-commit") - else - FIRSTLINE="" - fi - - say "$(eval_gettext "Applying: \$FIRSTLINE")" - - case "$resolved" in - '') - # When we are allowed to fall back to 3-way later, don't give - # false errors during the initial attempt. - squelch= - if test "$threeway" = t - then - squelch='>/dev/null 2>&1 ' - fi - eval "git apply $squelch$git_apply_opt"' --index "$dotest/patch"' - apply_status=$? - ;; - t) - # Resolved means the user did all the hard work, and - # we do not have to do any patch application. Just - # trust what the user has in the index file and the - # working tree. - resolved= - git diff-index --quiet --cached HEAD -- && { - gettextln "No changes - did you forget to use 'git add'? -If there is nothing left to stage, chances are that something else -already introduced the same changes; you might want to skip this patch." - stop_here_user_resolve $this - } - unmerged=$(git ls-files -u) - if test -n "$unmerged" - then - gettextln "You still have unmerged paths in your index -did you forget to use 'git add'?" - stop_here_user_resolve $this - fi - apply_status=0 - git rerere - ;; - esac - - if test $apply_status != 0 && test "$threeway" = t - then - if (fall_back_3way) - then - # Applying the patch to an earlier tree and merging the - # result may have produced the same tree as ours. - git diff-index --quiet --cached HEAD -- && { - say "$(gettext "No changes -- Patch already applied.")" - go_next - continue - } - # clear apply_status -- we have successfully merged. - apply_status=0 - fi - fi - if test $apply_status != 0 - then - eval_gettextln 'Patch failed at $msgnum $FIRSTLINE' - if test "$(git config --bool advice.amworkdir)" != false - then - eval_gettextln 'The copy of the patch that failed is found in: - $dotest/patch' - fi - stop_here_user_resolve $this - fi - - hook="$(git rev-parse --git-path hooks/pre-applypatch)" - if test -x "$hook" - then - "$hook" || stop_here $this - fi - - tree=$(git write-tree) && - commit=$( - if test -n "$ignore_date" - then - GIT_AUTHOR_DATE= - fi - parent=$(git rev-parse --verify -q HEAD) || - say >&2 "$(gettext "applying to an empty history")" - - if test -n "$committer_date_is_author_date" - then - GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" - export GIT_COMMITTER_DATE - fi && - git commit-tree ${parent:+-p} $parent ${gpg_sign_opt:+"$gpg_sign_opt"} $tree \ - <"$dotest/final-commit" - ) && - git update-ref -m "$GIT_REFLOG_ACTION: $FIRSTLINE" HEAD $commit $parent || - stop_here $this - - if test -f "$dotest/original-commit"; then - echo "$(cat "$dotest/original-commit") $commit" >> "$dotest/rewritten" - fi - - hook="$(git rev-parse --git-path hooks/post-applypatch)" - test -x "$hook" && "$hook" - - go_next -done - -if test -s "$dotest"/rewritten; then - git notes copy --for-rewrite=rebase < "$dotest"/rewritten - hook="$(git rev-parse --git-path hooks/post-rewrite)" - if test -x "$hook"; then - "$hook" rebase < "$dotest"/rewritten - fi -fi - -# If am was called with --rebasing (from git-rebase--am), it's up to -# the caller to take care of housekeeping. -if ! test -f "$dotest/rebasing" -then - rm -fr "$dotest" - git gc --auto -fi diff --git a/contrib/examples/git-checkout.sh b/contrib/examples/git-checkout.sh deleted file mode 100755 index 683cae7c3f..0000000000 --- a/contrib/examples/git-checkout.sh +++ /dev/null @@ -1,302 +0,0 @@ -#!/bin/sh - -OPTIONS_KEEPDASHDASH=t -OPTIONS_SPEC="\ -git-checkout [options] [<branch>] [<paths>...] --- -b= create a new branch started at <branch> -l create the new branch's reflog -track arrange that the new branch tracks the remote branch -f proceed even if the index or working tree is not HEAD -m merge local modifications into the new branch -q,quiet be quiet -" -SUBDIRECTORY_OK=Sometimes -. git-sh-setup -require_work_tree - -old_name=HEAD -old=$(git rev-parse --verify $old_name 2>/dev/null) -oldbranch=$(git symbolic-ref $old_name 2>/dev/null) -new= -new_name= -force= -branch= -track= -newbranch= -newbranch_log= -merge= -quiet= -v=-v -LF=' -' - -while test $# != 0; do - case "$1" in - -b) - shift - newbranch="$1" - [ -z "$newbranch" ] && - die "git checkout: -b needs a branch name" - git show-ref --verify --quiet -- "refs/heads/$newbranch" && - die "git checkout: branch $newbranch already exists" - git check-ref-format "heads/$newbranch" || - die "git checkout: we do not like '$newbranch' as a branch name." - ;; - -l) - newbranch_log=-l - ;; - --track|--no-track) - track="$1" - ;; - -f) - force=1 - ;; - -m) - merge=1 - ;; - -q|--quiet) - quiet=1 - v= - ;; - --) - shift - break - ;; - *) - usage - ;; - esac - shift -done - -arg="$1" -rev=$(git rev-parse --verify "$arg" 2>/dev/null) -if rev=$(git rev-parse --verify "$rev^0" 2>/dev/null) -then - [ -z "$rev" ] && die "unknown flag $arg" - new_name="$arg" - if git show-ref --verify --quiet -- "refs/heads/$arg" - then - rev=$(git rev-parse --verify "refs/heads/$arg^0") - branch="$arg" - fi - new="$rev" - shift -elif rev=$(git rev-parse --verify "$rev^{tree}" 2>/dev/null) -then - # checking out selected paths from a tree-ish. - new="$rev" - new_name="$rev^{tree}" - shift -fi -[ "$1" = "--" ] && shift - -case "$newbranch,$track" in -,--*) - die "git checkout: --track and --no-track require -b" -esac - -case "$force$merge" in -11) - die "git checkout: -f and -m are incompatible" -esac - -# The behaviour of the command with and without explicit path -# parameters is quite different. -# -# Without paths, we are checking out everything in the work tree, -# possibly switching branches. This is the traditional behaviour. -# -# With paths, we are _never_ switching branch, but checking out -# the named paths from either index (when no rev is given), -# or the named tree-ish (when rev is given). - -if test "$#" -ge 1 -then - hint= - if test "$#" -eq 1 - then - hint=" -Did you intend to checkout '$@' which can not be resolved as commit?" - fi - if test '' != "$newbranch$force$merge" - then - die "git checkout: updating paths is incompatible with switching branches/forcing$hint" - fi - if test '' != "$new" - then - # from a specific tree-ish; note that this is for - # rescuing paths and is never meant to remove what - # is not in the named tree-ish. - git ls-tree --full-name -r "$new" "$@" | - git update-index --index-info || exit $? - fi - - # Make sure the request is about existing paths. - git ls-files --full-name --error-unmatch -- "$@" >/dev/null || exit - git ls-files --full-name -- "$@" | - (cd_to_toplevel && git checkout-index -f -u --stdin) - - # Run a post-checkout hook -- the HEAD does not change so the - # current HEAD is passed in for both args - if test -x "$GIT_DIR"/hooks/post-checkout; then - "$GIT_DIR"/hooks/post-checkout $old $old 0 - fi - - exit $? -else - # Make sure we did not fall back on $arg^{tree} codepath - # since we are not checking out from an arbitrary tree-ish, - # but switching branches. - if test '' != "$new" - then - git rev-parse --verify "$new^{commit}" >/dev/null 2>&1 || - die "Cannot switch branch to a non-commit." - fi -fi - -# We are switching branches and checking out trees, so -# we *NEED* to be at the toplevel. -cd_to_toplevel - -[ -z "$new" ] && new=$old && new_name="$old_name" - -# If we don't have an existing branch that we're switching to, -# and we don't have a new branch name for the target we -# are switching to, then we are detaching our HEAD from any -# branch. However, if "git checkout HEAD" detaches the HEAD -# from the current branch, even though that may be logically -# correct, it feels somewhat funny. More importantly, we do not -# want "git checkout" or "git checkout -f" to detach HEAD. - -detached= -detach_warn= - -describe_detached_head () { - test -n "$quiet" || { - printf >&2 "$1 " - GIT_PAGER= git log >&2 -1 --pretty=oneline --abbrev-commit "$2" -- - } -} - -if test -z "$branch$newbranch" && test "$new_name" != "$old_name" -then - detached="$new" - if test -n "$oldbranch" && test -z "$quiet" - then - detach_warn="Note: moving to \"$new_name\" which isn't a local branch -If you want to create a new branch from this checkout, you may do so -(now or later) by using -b with the checkout command again. Example: - git checkout -b <new_branch_name>" - fi -elif test -z "$oldbranch" && test "$new" != "$old" -then - describe_detached_head 'Previous HEAD position was' "$old" -fi - -if [ "X$old" = X ] -then - if test -z "$quiet" - then - echo >&2 "warning: You appear to be on a branch yet to be born." - echo >&2 "warning: Forcing checkout of $new_name." - fi - force=1 -fi - -if [ "$force" ] -then - git read-tree $v --reset -u $new -else - git update-index --refresh >/dev/null - git read-tree $v -m -u --exclude-per-directory=.gitignore $old $new || ( - case "$merge,$v" in - ,*) - exit 1 ;; - 1,) - ;; # quiet - *) - echo >&2 "Falling back to 3-way merge..." ;; - esac - - # Match the index to the working tree, and do a three-way. - git diff-files --name-only | git update-index --remove --stdin && - work=$(git write-tree) && - git read-tree $v --reset -u $new || exit - - eval GITHEAD_$new='${new_name:-${branch:-$new}}' && - eval GITHEAD_$work=local && - export GITHEAD_$new GITHEAD_$work && - git merge-recursive $old -- $new $work - - # Do not register the cleanly merged paths in the index yet. - # this is not a real merge before committing, but just carrying - # the working tree changes along. - unmerged=$(git ls-files -u) - git read-tree $v --reset $new - case "$unmerged" in - '') ;; - *) - ( - z40=0000000000000000000000000000000000000000 - echo "$unmerged" | - sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /" - echo "$unmerged" - ) | git update-index --index-info - ;; - esac - exit 0 - ) - saved_err=$? - if test "$saved_err" = 0 && test -z "$quiet" - then - git diff-index --name-status "$new" - fi - (exit $saved_err) -fi - -# -# Switch the HEAD pointer to the new branch if we -# checked out a branch head, and remove any potential -# old MERGE_HEAD's (subsequent commits will clearly not -# be based on them, since we re-set the index) -# -if [ "$?" -eq 0 ]; then - if [ "$newbranch" ]; then - git branch $track $newbranch_log "$newbranch" "$new_name" || exit - branch="$newbranch" - fi - if test -n "$branch" - then - old_branch_name=$(expr "z$oldbranch" : 'zrefs/heads/\(.*\)') - GIT_DIR="$GIT_DIR" git symbolic-ref -m "checkout: moving from ${old_branch_name:-$old} to $branch" HEAD "refs/heads/$branch" - if test -n "$quiet" - then - true # nothing - elif test "refs/heads/$branch" = "$oldbranch" - then - echo >&2 "Already on branch \"$branch\"" - else - echo >&2 "Switched to${newbranch:+ a new} branch \"$branch\"" - fi - elif test -n "$detached" - then - old_branch_name=$(expr "z$oldbranch" : 'zrefs/heads/\(.*\)') - git update-ref --no-deref -m "checkout: moving from ${old_branch_name:-$old} to $arg" HEAD "$detached" || - die "Cannot detach HEAD" - if test -n "$detach_warn" - then - echo >&2 "$detach_warn" - fi - describe_detached_head 'HEAD is now at' HEAD - fi - rm -f "$GIT_DIR/MERGE_HEAD" -else - exit 1 -fi - -# Run a post-checkout hook -if test -x "$GIT_DIR"/hooks/post-checkout; then - "$GIT_DIR"/hooks/post-checkout $old $new 1 -fi diff --git a/contrib/examples/git-clean.sh b/contrib/examples/git-clean.sh deleted file mode 100755 index 01c95e9fe8..0000000000 --- a/contrib/examples/git-clean.sh +++ /dev/null @@ -1,118 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005-2006 Pavel Roskin -# - -OPTIONS_KEEPDASHDASH= -OPTIONS_SPEC="\ -git-clean [options] <paths>... - -Clean untracked files from the working directory - -When optional <paths>... arguments are given, the paths -affected are further limited to those that match them. --- -d remove directories as well -f override clean.requireForce and clean anyway -n don't remove anything, just show what would be done -q be quiet, only report errors -x remove ignored files as well -X remove only ignored files" - -SUBDIRECTORY_OK=Yes -. git-sh-setup -require_work_tree - -ignored= -ignoredonly= -cleandir= -rmf="rm -f --" -rmrf="rm -rf --" -rm_refuse="echo Not removing" -echo1="echo" - -disabled=$(git config --bool clean.requireForce) - -while test $# != 0 -do - case "$1" in - -d) - cleandir=1 - ;; - -f) - disabled=false - ;; - -n) - disabled=false - rmf="echo Would remove" - rmrf="echo Would remove" - rm_refuse="echo Would not remove" - echo1=":" - ;; - -q) - echo1=":" - ;; - -x) - ignored=1 - ;; - -X) - ignoredonly=1 - ;; - --) - shift - break - ;; - *) - usage # should not happen - ;; - esac - shift -done - -# requireForce used to default to false but now it defaults to true. -# IOW, lack of explicit "clean.requireForce = false" is taken as -# "clean.requireForce = true". -case "$disabled" in -"") - die "clean.requireForce not set and -n or -f not given; refusing to clean" - ;; -"true") - die "clean.requireForce set and -n or -f not given; refusing to clean" - ;; -esac - -if [ "$ignored,$ignoredonly" = "1,1" ]; then - die "-x and -X cannot be set together" -fi - -if [ -z "$ignored" ]; then - excl="--exclude-per-directory=.gitignore" - excl_info= excludes_file= - if [ -f "$GIT_DIR/info/exclude" ]; then - excl_info="--exclude-from=$GIT_DIR/info/exclude" - fi - if cfg_excl=$(git config core.excludesfile) && test -f "$cfg_excl" - then - excludes_file="--exclude-from=$cfg_excl" - fi - if [ "$ignoredonly" ]; then - excl="$excl --ignored" - fi -fi - -git ls-files --others --directory \ - $excl ${excl_info:+"$excl_info"} ${excludes_file:+"$excludes_file"} \ - -- "$@" | -while read -r file; do - if [ -d "$file" -a ! -L "$file" ]; then - if [ -z "$cleandir" ]; then - $rm_refuse "$file" - continue - fi - $echo1 "Removing $file" - $rmrf "$file" - else - $echo1 "Removing $file" - $rmf "$file" - fi -done diff --git a/contrib/examples/git-clone.sh b/contrib/examples/git-clone.sh deleted file mode 100755 index 08cf246bbb..0000000000 --- a/contrib/examples/git-clone.sh +++ /dev/null @@ -1,525 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005, Linus Torvalds -# Copyright (c) 2005, Junio C Hamano -# -# Clone a repository into a different directory that does not yet exist. - -# See git-sh-setup why. -unset CDPATH - -OPTIONS_SPEC="\ -git-clone [options] [--] <repo> [<dir>] --- -n,no-checkout don't create a checkout -bare create a bare repository -naked create a bare repository -l,local to clone from a local repository -no-hardlinks don't use local hardlinks, always copy -s,shared setup as a shared repository -template= path to the template directory -q,quiet be quiet -reference= reference repository -o,origin= use <name> instead of 'origin' to track upstream -u,upload-pack= path to git-upload-pack on the remote -depth= create a shallow clone of that depth - -use-separate-remote compatibility, do not use -no-separate-remote compatibility, do not use" - -die() { - echo >&2 "$@" - exit 1 -} - -usage() { - exec "$0" -h -} - -eval "$(echo "$OPTIONS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)" - -get_repo_base() { - ( - cd "$(/bin/pwd)" && - cd "$1" || cd "$1.git" && - { - cd .git - pwd - } - ) 2>/dev/null -} - -if [ -n "$GIT_SSL_NO_VERIFY" -o \ - "$(git config --bool http.sslVerify)" = false ]; then - curl_extra_args="-k" -fi - -http_fetch () { - # $1 = Remote, $2 = Local - curl -nsfL $curl_extra_args "$1" >"$2" - curl_exit_status=$? - case $curl_exit_status in - 126|127) exit ;; - *) return $curl_exit_status ;; - esac -} - -clone_dumb_http () { - # $1 - remote, $2 - local - cd "$2" && - clone_tmp="$GIT_DIR/clone-tmp" && - mkdir -p "$clone_tmp" || exit 1 - if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \ - "$(git config --bool http.noEPSV)" = true ]; then - curl_extra_args="${curl_extra_args} --disable-epsv" - fi - http_fetch "$1/info/refs" "$clone_tmp/refs" || - die "Cannot get remote repository information. -Perhaps git-update-server-info needs to be run there?" - test "z$quiet" = z && v=-v || v= - while read sha1 refname - do - name=$(expr "z$refname" : 'zrefs/\(.*\)') && - case "$name" in - *^*) continue;; - esac - case "$bare,$name" in - yes,* | ,heads/* | ,tags/*) ;; - *) continue ;; - esac - if test -n "$use_separate_remote" && - branch_name=$(expr "z$name" : 'zheads/\(.*\)') - then - tname="remotes/$origin/$branch_name" - else - tname=$name - fi - git-http-fetch $v -a -w "$tname" "$sha1" "$1" || exit 1 - done <"$clone_tmp/refs" - rm -fr "$clone_tmp" - http_fetch "$1/HEAD" "$GIT_DIR/REMOTE_HEAD" || - rm -f "$GIT_DIR/REMOTE_HEAD" - if test -f "$GIT_DIR/REMOTE_HEAD"; then - head_sha1=$(cat "$GIT_DIR/REMOTE_HEAD") - case "$head_sha1" in - 'ref: refs/'*) - ;; - *) - git-http-fetch $v -a "$head_sha1" "$1" || - rm -f "$GIT_DIR/REMOTE_HEAD" - ;; - esac - fi -} - -quiet= -local=no -use_local_hardlink=yes -local_shared=no -unset template -no_checkout= -upload_pack= -bare= -reference= -origin= -origin_override= -use_separate_remote=t -depth= -no_progress= -local_explicitly_asked_for= -test -t 1 || no_progress=--no-progress - -while test $# != 0 -do - case "$1" in - -n|--no-checkout) - no_checkout=yes ;; - --naked|--bare) - bare=yes ;; - -l|--local) - local_explicitly_asked_for=yes - use_local_hardlink=yes - ;; - --no-hardlinks) - use_local_hardlink=no ;; - -s|--shared) - local_shared=yes ;; - --template) - shift; template="--template=$1" ;; - -q|--quiet) - quiet=-q ;; - --use-separate-remote|--no-separate-remote) - die "clones are always made with separate-remote layout" ;; - --reference) - shift; reference="$1" ;; - -o|--origin) - shift; - case "$1" in - '') - usage ;; - */*) - die "'$1' is not suitable for an origin name" - esac - git check-ref-format "heads/$1" || - die "'$1' is not suitable for a branch name" - test -z "$origin_override" || - die "Do not give more than one --origin options." - origin_override=yes - origin="$1" - ;; - -u|--upload-pack) - shift - upload_pack="--upload-pack=$1" ;; - --depth) - shift - depth="--depth=$1" ;; - --) - shift - break ;; - *) - usage ;; - esac - shift -done - -repo="$1" -test -n "$repo" || - die 'you must specify a repository to clone.' - -# --bare implies --no-checkout and --no-separate-remote -if test yes = "$bare" -then - if test yes = "$origin_override" - then - die '--bare and --origin $origin options are incompatible.' - fi - no_checkout=yes - use_separate_remote= -fi - -if test -z "$origin" -then - origin=origin -fi - -# Turn the source into an absolute path if -# it is local -if base=$(get_repo_base "$repo"); then - repo="$base" - if test -z "$depth" - then - local=yes - fi -elif test -f "$repo" -then - case "$repo" in /*) ;; *) repo="$PWD/$repo" ;; esac -fi - -# Decide the directory name of the new repository -if test -n "$2" -then - dir="$2" - test $# = 2 || die "excess parameter to git-clone" -else - # Derive one from the repository name - # Try using "humanish" part of source repo if user didn't specify one - if test -f "$repo" - then - # Cloning from a bundle - dir=$(echo "$repo" | sed -e 's|/*\.bundle$||' -e 's|.*/||g') - else - dir=$(echo "$repo" | - sed -e 's|/$||' -e 's|:*/*\.git$||' -e 's|.*[/:]||g') - fi -fi - -[ -e "$dir" ] && die "destination directory '$dir' already exists." -[ yes = "$bare" ] && unset GIT_WORK_TREE -[ -n "$GIT_WORK_TREE" ] && [ -e "$GIT_WORK_TREE" ] && -die "working tree '$GIT_WORK_TREE' already exists." -D= -W= -cleanup() { - test -z "$D" && rm -rf "$dir" - test -z "$W" && test -n "$GIT_WORK_TREE" && rm -rf "$GIT_WORK_TREE" - cd .. - test -n "$D" && rm -rf "$D" - test -n "$W" && rm -rf "$W" - exit $err -} -trap 'err=$?; cleanup' 0 -mkdir -p "$dir" && D=$(cd "$dir" && pwd) || usage -test -n "$GIT_WORK_TREE" && mkdir -p "$GIT_WORK_TREE" && -W=$(cd "$GIT_WORK_TREE" && pwd) && GIT_WORK_TREE="$W" && export GIT_WORK_TREE -if test yes = "$bare" || test -n "$GIT_WORK_TREE"; then - GIT_DIR="$D" -else - GIT_DIR="$D/.git" -fi && -export GIT_DIR && -GIT_CONFIG="$GIT_DIR/config" git-init $quiet ${template+"$template"} || usage - -if test -n "$bare" -then - GIT_CONFIG="$GIT_DIR/config" git config core.bare true -fi - -if test -n "$reference" -then - ref_git= - if test -d "$reference" - then - if test -d "$reference/.git/objects" - then - ref_git="$reference/.git" - elif test -d "$reference/objects" - then - ref_git="$reference" - fi - fi - if test -n "$ref_git" - then - ref_git=$(cd "$ref_git" && pwd) - echo "$ref_git/objects" >"$GIT_DIR/objects/info/alternates" - ( - GIT_DIR="$ref_git" git for-each-ref \ - --format='%(objectname) %(*objectname)' - ) | - while read a b - do - test -z "$a" || - git update-ref "refs/reference-tmp/$a" "$a" - test -z "$b" || - git update-ref "refs/reference-tmp/$b" "$b" - done - else - die "reference repository '$reference' is not a local directory." - fi -fi - -rm -f "$GIT_DIR/CLONE_HEAD" - -# We do local magic only when the user tells us to. -case "$local" in -yes) - ( cd "$repo/objects" ) || - die "cannot chdir to local '$repo/objects'." - - if test "$local_shared" = yes - then - mkdir -p "$GIT_DIR/objects/info" - echo "$repo/objects" >>"$GIT_DIR/objects/info/alternates" - else - cpio_quiet_flag="" - cpio --help 2>&1 | grep -- --quiet >/dev/null && \ - cpio_quiet_flag=--quiet - l= && - if test "$use_local_hardlink" = yes - then - # See if we can hardlink and drop "l" if not. - sample_file=$(cd "$repo" && \ - find objects -type f -print | sed -e 1q) - # objects directory should not be empty because - # we are cloning! - test -f "$repo/$sample_file" || - die "fatal: cannot clone empty repository" - if ln "$repo/$sample_file" "$GIT_DIR/objects/sample" 2>/dev/null - then - rm -f "$GIT_DIR/objects/sample" - l=l - elif test -n "$local_explicitly_asked_for" - then - echo >&2 "Warning: -l asked but cannot hardlink to $repo" - fi - fi && - cd "$repo" && - # Create dirs using umask and permissions and destination - find objects -type d -print | (cd "$GIT_DIR" && xargs mkdir -p) && - # Copy existing 0444 permissions on content - find objects ! -type d -print | cpio $cpio_quiet_flag -pumd$l "$GIT_DIR/" || \ - exit 1 - fi - git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1 - ;; -*) - case "$repo" in - rsync://*) - case "$depth" in - "") ;; - *) die "shallow over rsync not supported" ;; - esac - rsync $quiet -av --ignore-existing \ - --exclude info "$repo/objects/" "$GIT_DIR/objects/" || - exit - # Look at objects/info/alternates for rsync -- http will - # support it natively and git native ones will do it on the - # remote end. Not having that file is not a crime. - rsync -q "$repo/objects/info/alternates" \ - "$GIT_DIR/TMP_ALT" 2>/dev/null || - rm -f "$GIT_DIR/TMP_ALT" - if test -f "$GIT_DIR/TMP_ALT" - then - ( cd "$D" && - . git-parse-remote && - resolve_alternates "$repo" <"$GIT_DIR/TMP_ALT" ) | - while read alt - do - case "$alt" in 'bad alternate: '*) die "$alt";; esac - case "$quiet" in - '') echo >&2 "Getting alternate: $alt" ;; - esac - rsync $quiet -av --ignore-existing \ - --exclude info "$alt" "$GIT_DIR/objects" || exit - done - rm -f "$GIT_DIR/TMP_ALT" - fi - git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1 - ;; - https://*|http://*|ftp://*) - case "$depth" in - "") ;; - *) die "shallow over http or ftp not supported" ;; - esac - if test -z "@@NO_CURL@@" - then - clone_dumb_http "$repo" "$D" - else - die "http transport not supported, rebuild Git with curl support" - fi - ;; - *) - if [ -f "$repo" ] ; then - git bundle unbundle "$repo" > "$GIT_DIR/CLONE_HEAD" || - die "unbundle from '$repo' failed." - else - case "$upload_pack" in - '') git-fetch-pack --all -k $quiet $depth $no_progress "$repo";; - *) git-fetch-pack --all -k \ - $quiet "$upload_pack" $depth $no_progress "$repo" ;; - esac >"$GIT_DIR/CLONE_HEAD" || - die "fetch-pack from '$repo' failed." - fi - ;; - esac - ;; -esac -test -d "$GIT_DIR/refs/reference-tmp" && rm -fr "$GIT_DIR/refs/reference-tmp" - -if test -f "$GIT_DIR/CLONE_HEAD" -then - # Read git-fetch-pack -k output and store the remote branches. - if [ -n "$use_separate_remote" ] - then - branch_top="remotes/$origin" - else - branch_top="heads" - fi - tag_top="tags" - while read sha1 name - do - case "$name" in - *'^{}') - continue ;; - HEAD) - destname="REMOTE_HEAD" ;; - refs/heads/*) - destname="refs/$branch_top/${name#refs/heads/}" ;; - refs/tags/*) - destname="refs/$tag_top/${name#refs/tags/}" ;; - *) - continue ;; - esac - git update-ref -m "clone: from $repo" "$destname" "$sha1" "" - done < "$GIT_DIR/CLONE_HEAD" -fi - -if test -n "$W"; then - cd "$W" || exit -else - cd "$D" || exit -fi - -if test -z "$bare" -then - # a non-bare repository is always in separate-remote layout - remote_top="refs/remotes/$origin" - head_sha1= - test ! -r "$GIT_DIR/REMOTE_HEAD" || head_sha1=$(cat "$GIT_DIR/REMOTE_HEAD") - case "$head_sha1" in - 'ref: refs/'*) - # Uh-oh, the remote told us (http transport done against - # new style repository with a symref HEAD). - # Ideally we should skip the guesswork but for now - # opt for minimum change. - head_sha1=$(expr "z$head_sha1" : 'zref: refs/heads/\(.*\)') - head_sha1=$(cat "$GIT_DIR/$remote_top/$head_sha1") - ;; - esac - - # The name under $remote_top the remote HEAD seems to point at. - head_points_at=$( - ( - test -f "$GIT_DIR/$remote_top/master" && echo "master" - cd "$GIT_DIR/$remote_top" && - find . -type f -print | sed -e 's/^\.\///' - ) | ( - done=f - while read name - do - test t = $done && continue - branch_tip=$(cat "$GIT_DIR/$remote_top/$name") - if test "$head_sha1" = "$branch_tip" - then - echo "$name" - done=t - fi - done - ) - ) - - # Upstream URL - git config remote."$origin".url "$repo" && - - # Set up the mappings to track the remote branches. - git config remote."$origin".fetch \ - "+refs/heads/*:$remote_top/*" '^$' && - - # Write out remote.$origin config, and update our "$head_points_at". - case "$head_points_at" in - ?*) - # Local default branch - git symbolic-ref HEAD "refs/heads/$head_points_at" && - - # Tracking branch for the primary branch at the remote. - git update-ref HEAD "$head_sha1" && - - rm -f "refs/remotes/$origin/HEAD" - git symbolic-ref "refs/remotes/$origin/HEAD" \ - "refs/remotes/$origin/$head_points_at" && - - git config branch."$head_points_at".remote "$origin" && - git config branch."$head_points_at".merge "refs/heads/$head_points_at" - ;; - '') - if test -z "$head_sha1" - then - # Source had nonexistent ref in HEAD - echo >&2 "Warning: Remote HEAD refers to nonexistent ref, unable to checkout." - no_checkout=t - else - # Source had detached HEAD pointing nowhere - git update-ref --no-deref HEAD "$head_sha1" && - rm -f "refs/remotes/$origin/HEAD" - fi - ;; - esac - - case "$no_checkout" in - '') - test "z$quiet" = z && test "z$no_progress" = z && v=-v || v= - git read-tree -m -u $v HEAD HEAD - esac -fi -rm -f "$GIT_DIR/CLONE_HEAD" "$GIT_DIR/REMOTE_HEAD" - -trap - 0 diff --git a/contrib/examples/git-commit.sh b/contrib/examples/git-commit.sh deleted file mode 100755 index 86c9cfa0c7..0000000000 --- a/contrib/examples/git-commit.sh +++ /dev/null @@ -1,639 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005 Linus Torvalds -# Copyright (c) 2006 Junio C Hamano - -USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]' -SUBDIRECTORY_OK=Yes -OPTIONS_SPEC= -. git-sh-setup -require_work_tree - -git rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t - -case "$0" in -*status) - status_only=t - ;; -*commit) - status_only= - ;; -esac - -refuse_partial () { - echo >&2 "$1" - echo >&2 "You might have meant to say 'git commit -i paths...', perhaps?" - exit 1 -} - -TMP_INDEX= -THIS_INDEX="${GIT_INDEX_FILE:-$GIT_DIR/index}" -NEXT_INDEX="$GIT_DIR/next-index$$" -rm -f "$NEXT_INDEX" -save_index () { - cp -p "$THIS_INDEX" "$NEXT_INDEX" -} - -run_status () { - # If TMP_INDEX is defined, that means we are doing - # "--only" partial commit, and that index file is used - # to build the tree for the commit. Otherwise, if - # NEXT_INDEX exists, that is the index file used to - # make the commit. Otherwise we are using as-is commit - # so the regular index file is what we use to compare. - if test '' != "$TMP_INDEX" - then - GIT_INDEX_FILE="$TMP_INDEX" - export GIT_INDEX_FILE - elif test -f "$NEXT_INDEX" - then - GIT_INDEX_FILE="$NEXT_INDEX" - export GIT_INDEX_FILE - fi - - if test "$status_only" = "t" || test "$use_status_color" = "t"; then - color= - else - color=--nocolor - fi - git runstatus ${color} \ - ${verbose:+--verbose} \ - ${amend:+--amend} \ - ${untracked_files:+--untracked} -} - -trap ' - test -z "$TMP_INDEX" || { - test -f "$TMP_INDEX" && rm -f "$TMP_INDEX" - } - rm -f "$NEXT_INDEX" -' 0 - -################################################################ -# Command line argument parsing and sanity checking - -all= -also= -allow_empty=f -interactive= -only= -logfile= -use_commit= -amend= -edit_flag= -no_edit= -log_given= -log_message= -verify=t -quiet= -verbose= -signoff= -force_author= -only_include_assumed= -untracked_files= -templatefile="$(git config commit.template)" -while test $# != 0 -do - case "$1" in - -F|--F|-f|--f|--fi|--fil|--file) - case "$#" in 1) usage ;; esac - shift - no_edit=t - log_given=t$log_given - logfile="$1" - ;; - -F*|-f*) - no_edit=t - log_given=t$log_given - logfile="${1#-[Ff]}" - ;; - --F=*|--f=*|--fi=*|--fil=*|--file=*) - no_edit=t - log_given=t$log_given - logfile="${1#*=}" - ;; - -a|--a|--al|--all) - all=t - ;; - --allo|--allow|--allow-|--allow-e|--allow-em|--allow-emp|\ - --allow-empt|--allow-empty) - allow_empty=t - ;; - --au=*|--aut=*|--auth=*|--autho=*|--author=*) - force_author="${1#*=}" - ;; - --au|--aut|--auth|--autho|--author) - case "$#" in 1) usage ;; esac - shift - force_author="$1" - ;; - -e|--e|--ed|--edi|--edit) - edit_flag=t - ;; - -i|--i|--in|--inc|--incl|--inclu|--includ|--include) - also=t - ;; - --int|--inte|--inter|--intera|--interac|--interact|--interacti|\ - --interactiv|--interactive) - interactive=t - ;; - -o|--o|--on|--onl|--only) - only=t - ;; - -m|--m|--me|--mes|--mess|--messa|--messag|--message) - case "$#" in 1) usage ;; esac - shift - log_given=m$log_given - log_message="${log_message:+${log_message} - -}$1" - no_edit=t - ;; - -m*) - log_given=m$log_given - log_message="${log_message:+${log_message} - -}${1#-m}" - no_edit=t - ;; - --m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*) - log_given=m$log_given - log_message="${log_message:+${log_message} - -}${1#*=}" - no_edit=t - ;; - -n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|\ - --no-verify) - verify= - ;; - --a|--am|--ame|--amen|--amend) - amend=t - use_commit=HEAD - ;; - -c) - case "$#" in 1) usage ;; esac - shift - log_given=t$log_given - use_commit="$1" - no_edit= - ;; - --ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\ - --reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\ - --reedit-messag=*|--reedit-message=*) - log_given=t$log_given - use_commit="${1#*=}" - no_edit= - ;; - --ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\ - --reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|\ - --reedit-message) - case "$#" in 1) usage ;; esac - shift - log_given=t$log_given - use_commit="$1" - no_edit= - ;; - -C) - case "$#" in 1) usage ;; esac - shift - log_given=t$log_given - use_commit="$1" - no_edit=t - ;; - --reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\ - --reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\ - --reuse-message=*) - log_given=t$log_given - use_commit="${1#*=}" - no_edit=t - ;; - --reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\ - --reuse-mess|--reuse-messa|--reuse-messag|--reuse-message) - case "$#" in 1) usage ;; esac - shift - log_given=t$log_given - use_commit="$1" - no_edit=t - ;; - -s|--s|--si|--sig|--sign|--signo|--signof|--signoff) - signoff=t - ;; - -t|--t|--te|--tem|--temp|--templ|--templa|--templat|--template) - case "$#" in 1) usage ;; esac - shift - templatefile="$1" - no_edit= - ;; - -q|--q|--qu|--qui|--quie|--quiet) - quiet=t - ;; - -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose) - verbose=t - ;; - -u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|\ - --untracked|--untracked-|--untracked-f|--untracked-fi|--untracked-fil|\ - --untracked-file|--untracked-files) - untracked_files=t - ;; - --) - shift - break - ;; - -*) - usage - ;; - *) - break - ;; - esac - shift -done -case "$edit_flag" in t) no_edit= ;; esac - -################################################################ -# Sanity check options - -case "$amend,$initial_commit" in -t,t) - die "You do not have anything to amend." ;; -t,) - if [ -f "$GIT_DIR/MERGE_HEAD" ]; then - die "You are in the middle of a merge -- cannot amend." - fi ;; -esac - -case "$log_given" in -tt*) - die "Only one of -c/-C/-F can be used." ;; -*tm*|*mt*) - die "Option -m cannot be combined with -c/-C/-F." ;; -esac - -case "$#,$also,$only,$amend" in -*,t,t,*) - die "Only one of --include/--only can be used." ;; -0,t,,* | 0,,t,) - die "No paths with --include/--only does not make sense." ;; -0,,t,t) - only_include_assumed="# Clever... amending the last one with dirty index." ;; -0,,,*) - ;; -*,,,*) - only_include_assumed="# Explicit paths specified without -i or -o; assuming --only paths..." - also= - ;; -esac -unset only -case "$all,$interactive,$also,$#" in -*t,*t,*) - die "Cannot use -a, --interactive or -i at the same time." ;; -t,,,[1-9]*) - die "Paths with -a does not make sense." ;; -,t,,[1-9]*) - die "Paths with --interactive does not make sense." ;; -,,t,0) - die "No paths with -i does not make sense." ;; -esac - -if test ! -z "$templatefile" && test -z "$log_given" -then - if test ! -f "$templatefile" - then - die "Commit template file does not exist." - fi -fi - -################################################################ -# Prepare index to have a tree to be committed - -case "$all,$also" in -t,) - if test ! -f "$THIS_INDEX" - then - die 'nothing to commit (use "git add file1 file2" to include for commit)' - fi - save_index && - ( - cd_to_toplevel && - GIT_INDEX_FILE="$NEXT_INDEX" && - export GIT_INDEX_FILE && - git diff-files --name-only -z | - git update-index --remove -z --stdin - ) || exit - ;; -,t) - save_index && - git ls-files --error-unmatch -- "$@" >/dev/null || exit - - git diff-files --name-only -z -- "$@" | - ( - cd_to_toplevel && - GIT_INDEX_FILE="$NEXT_INDEX" && - export GIT_INDEX_FILE && - git update-index --remove -z --stdin - ) || exit - ;; -,) - if test "$interactive" = t; then - git add --interactive || exit - fi - case "$#" in - 0) - ;; # commit as-is - *) - if test -f "$GIT_DIR/MERGE_HEAD" - then - refuse_partial "Cannot do a partial commit during a merge." - fi - - TMP_INDEX="$GIT_DIR/tmp-index$$" - W= - test -z "$initial_commit" && W=--with-tree=HEAD - commit_only=$(git ls-files --error-unmatch $W -- "$@") || exit - - # Build a temporary index and update the real index - # the same way. - if test -z "$initial_commit" - then - GIT_INDEX_FILE="$THIS_INDEX" \ - git read-tree --index-output="$TMP_INDEX" -i -m HEAD - else - rm -f "$TMP_INDEX" - fi || exit - - printf '%s\n' "$commit_only" | - GIT_INDEX_FILE="$TMP_INDEX" \ - git update-index --add --remove --stdin && - - save_index && - printf '%s\n' "$commit_only" | - ( - GIT_INDEX_FILE="$NEXT_INDEX" - export GIT_INDEX_FILE - git update-index --add --remove --stdin - ) || exit - ;; - esac - ;; -esac - -################################################################ -# If we do as-is commit, the index file will be THIS_INDEX, -# otherwise NEXT_INDEX after we make this commit. We leave -# the index as is if we abort. - -if test -f "$NEXT_INDEX" -then - USE_INDEX="$NEXT_INDEX" -else - USE_INDEX="$THIS_INDEX" -fi - -case "$status_only" in -t) - # This will silently fail in a read-only repository, which is - # what we want. - GIT_INDEX_FILE="$USE_INDEX" git update-index -q --unmerged --refresh - run_status - exit $? - ;; -'') - GIT_INDEX_FILE="$USE_INDEX" git update-index -q --refresh || exit - ;; -esac - -################################################################ -# Grab commit message, write out tree and make commit. - -if test t = "$verify" && test -x "$GIT_DIR"/hooks/pre-commit -then - GIT_INDEX_FILE="${TMP_INDEX:-${USE_INDEX}}" "$GIT_DIR"/hooks/pre-commit \ - || exit -fi - -if test "$log_message" != '' -then - printf '%s\n' "$log_message" -elif test "$logfile" != "" -then - if test "$logfile" = - - then - test -t 0 && - echo >&2 "(reading log message from standard input)" - cat - else - cat <"$logfile" - fi -elif test "$use_commit" != "" -then - encoding=$(git config i18n.commitencoding || echo UTF-8) - git show -s --pretty=raw --encoding="$encoding" "$use_commit" | - sed -e '1,/^$/d' -e 's/^ //' -elif test -f "$GIT_DIR/MERGE_MSG" -then - cat "$GIT_DIR/MERGE_MSG" -elif test -f "$GIT_DIR/SQUASH_MSG" -then - cat "$GIT_DIR/SQUASH_MSG" -elif test "$templatefile" != "" -then - cat "$templatefile" -fi | git stripspace >"$GIT_DIR"/COMMIT_EDITMSG - -case "$signoff" in -t) - sign=$(git var GIT_COMMITTER_IDENT | sed -e ' - s/>.*/>/ - s/^/Signed-off-by: / - ') - blank_before_signoff= - tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG | - grep 'Signed-off-by:' >/dev/null || blank_before_signoff=' -' - tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG | - grep "$sign"$ >/dev/null || - printf '%s%s\n' "$blank_before_signoff" "$sign" \ - >>"$GIT_DIR"/COMMIT_EDITMSG - ;; -esac - -if test -f "$GIT_DIR/MERGE_HEAD" && test -z "$no_edit"; then - echo "#" - echo "# It looks like you may be committing a MERGE." - echo "# If this is not correct, please remove the file" - printf '%s\n' "# $GIT_DIR/MERGE_HEAD" - echo "# and try again" - echo "#" -fi >>"$GIT_DIR"/COMMIT_EDITMSG - -# Author -if test '' != "$use_commit" -then - eval "$(get_author_ident_from_commit "$use_commit")" - export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE -fi -if test '' != "$force_author" -then - GIT_AUTHOR_NAME=$(expr "z$force_author" : 'z\(.*[^ ]\) *<.*') && - GIT_AUTHOR_EMAIL=$(expr "z$force_author" : '.*\(<.*\)') && - test '' != "$GIT_AUTHOR_NAME" && - test '' != "$GIT_AUTHOR_EMAIL" || - die "malformed --author parameter" - export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL -fi - -PARENTS="-p HEAD" -if test -z "$initial_commit" -then - rloga='commit' - if [ -f "$GIT_DIR/MERGE_HEAD" ]; then - rloga='commit (merge)' - PARENTS="-p HEAD "$(sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD") - elif test -n "$amend"; then - rloga='commit (amend)' - PARENTS=$(git cat-file commit HEAD | - sed -n -e '/^$/q' -e 's/^parent /-p /p') - fi - current="$(git rev-parse --verify HEAD)" -else - if [ -z "$(git ls-files)" ]; then - echo >&2 'nothing to commit (use "git add file1 file2" to include for commit)' - exit 1 - fi - PARENTS="" - rloga='commit (initial)' - current='' -fi -set_reflog_action "$rloga" - -if test -z "$no_edit" -then - { - echo "" - echo "# Please enter the commit message for your changes." - echo "# (Comment lines starting with '#' will not be included)" - test -z "$only_include_assumed" || echo "$only_include_assumed" - run_status - } >>"$GIT_DIR"/COMMIT_EDITMSG -else - # we need to check if there is anything to commit - run_status >/dev/null -fi -case "$allow_empty,$?,$PARENTS" in -t,* | ?,0,* | ?,*,-p' '?*-p' '?*) - # an explicit --allow-empty, or a merge commit can record the - # same tree as its parent. Otherwise having commitable paths - # is required. - ;; -*) - rm -f "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG" - use_status_color=t - run_status - exit 1 -esac - -case "$no_edit" in -'') - git var GIT_AUTHOR_IDENT > /dev/null || die - git var GIT_COMMITTER_IDENT > /dev/null || die - git_editor "$GIT_DIR/COMMIT_EDITMSG" - ;; -esac - -case "$verify" in -t) - if test -x "$GIT_DIR"/hooks/commit-msg - then - "$GIT_DIR"/hooks/commit-msg "$GIT_DIR"/COMMIT_EDITMSG || exit - fi -esac - -if test -z "$no_edit" -then - sed -e ' - /^diff --git a\/.*/{ - s/// - q - } - /^#/d - ' "$GIT_DIR"/COMMIT_EDITMSG -else - cat "$GIT_DIR"/COMMIT_EDITMSG -fi | -git stripspace >"$GIT_DIR"/COMMIT_MSG - -# Test whether the commit message has any content we didn't supply. -have_commitmsg= -grep -v -i '^Signed-off-by' "$GIT_DIR"/COMMIT_MSG | - git stripspace > "$GIT_DIR"/COMMIT_BAREMSG - -# Is the commit message totally empty? -if test -s "$GIT_DIR"/COMMIT_BAREMSG -then - if test "$templatefile" != "" - then - # Test whether this is just the unaltered template. - if cnt=$(sed -e '/^#/d' < "$templatefile" | - git stripspace | - diff "$GIT_DIR"/COMMIT_BAREMSG - | - wc -l) && - test 0 -lt $cnt - then - have_commitmsg=t - fi - else - # No template, so the content in the commit message must - # have come from the user. - have_commitmsg=t - fi -fi - -rm -f "$GIT_DIR"/COMMIT_BAREMSG - -if test "$have_commitmsg" = "t" -then - if test -z "$TMP_INDEX" - then - tree=$(GIT_INDEX_FILE="$USE_INDEX" git write-tree) - else - tree=$(GIT_INDEX_FILE="$TMP_INDEX" git write-tree) && - rm -f "$TMP_INDEX" - fi && - commit=$(git commit-tree $tree $PARENTS <"$GIT_DIR/COMMIT_MSG") && - rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) && - git update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" && - rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" && - if test -f "$NEXT_INDEX" - then - mv "$NEXT_INDEX" "$THIS_INDEX" - else - : ;# happy - fi -else - echo >&2 "* no commit message? aborting commit." - false -fi -ret="$?" -rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG" - -cd_to_toplevel - -git rerere - -if test "$ret" = 0 -then - git gc --auto - if test -x "$GIT_DIR"/hooks/post-commit - then - "$GIT_DIR"/hooks/post-commit - fi - if test -z "$quiet" - then - commit=$(git diff-tree --always --shortstat --pretty="format:%h: %s"\ - --abbrev --summary --root HEAD --) - echo "Created${initial_commit:+ initial} commit $commit" - fi -fi - -exit "$ret" diff --git a/contrib/examples/git-difftool.perl b/contrib/examples/git-difftool.perl deleted file mode 100755 index fb0fd0b84b..0000000000 --- a/contrib/examples/git-difftool.perl +++ /dev/null @@ -1,481 +0,0 @@ -#!/usr/bin/perl -# Copyright (c) 2009, 2010 David Aguilar -# Copyright (c) 2012 Tim Henigan -# -# This is a wrapper around the GIT_EXTERNAL_DIFF-compatible -# git-difftool--helper script. -# -# This script exports GIT_EXTERNAL_DIFF and GIT_PAGER for use by git. -# The GIT_DIFF* variables are exported for use by git-difftool--helper. -# -# Any arguments that are unknown to this script are forwarded to 'git diff'. - -use 5.008; -use strict; -use warnings; -use Git::Error qw(:try); -use File::Basename qw(dirname); -use File::Copy; -use File::Find; -use File::stat; -use File::Path qw(mkpath rmtree); -use File::Temp qw(tempdir); -use Getopt::Long qw(:config pass_through); -use Git; -use Git::I18N; - -sub usage -{ - my $exitcode = shift; - print << 'USAGE'; -usage: git difftool [-t|--tool=<tool>] [--tool-help] - [-x|--extcmd=<cmd>] - [-g|--gui] [--no-gui] - [--prompt] [-y|--no-prompt] - [-d|--dir-diff] - ['git diff' options] -USAGE - exit($exitcode); -} - -sub print_tool_help -{ - # See the comment at the bottom of file_diff() for the reason behind - # using system() followed by exit() instead of exec(). - my $rc = system(qw(git mergetool --tool-help=diff)); - exit($rc | ($rc >> 8)); -} - -sub exit_cleanup -{ - my ($tmpdir, $status) = @_; - my $errno = $!; - rmtree($tmpdir); - if ($status and $errno) { - my ($package, $file, $line) = caller(); - warn "$file line $line: $errno\n"; - } - exit($status | ($status >> 8)); -} - -sub use_wt_file -{ - my ($file, $sha1) = @_; - my $null_sha1 = '0' x 40; - - if (-l $file || ! -e _) { - return (0, $null_sha1); - } - - my $wt_sha1 = Git::command_oneline('hash-object', $file); - my $use = ($sha1 eq $null_sha1) || ($sha1 eq $wt_sha1); - return ($use, $wt_sha1); -} - -sub changed_files -{ - my ($repo_path, $index, $worktree) = @_; - $ENV{GIT_INDEX_FILE} = $index; - - my @gitargs = ('--git-dir', $repo_path, '--work-tree', $worktree); - my @refreshargs = ( - @gitargs, 'update-index', - '--really-refresh', '-q', '--unmerged'); - try { - Git::command_oneline(@refreshargs); - } catch Git::Error::Command with {}; - - my @diffargs = (@gitargs, 'diff-files', '--name-only', '-z'); - my $line = Git::command_oneline(@diffargs); - my @files; - if (defined $line) { - @files = split('\0', $line); - } else { - @files = (); - } - - delete($ENV{GIT_INDEX_FILE}); - - return map { $_ => 1 } @files; -} - -sub setup_dir_diff -{ - my ($worktree, $symlinks) = @_; - my @gitargs = ('diff', '--raw', '--no-abbrev', '-z', @ARGV); - my $diffrtn = Git::command_oneline(@gitargs); - exit(0) unless defined($diffrtn); - - # Go to the root of the worktree now that we've captured the list of - # changed files. The paths returned by diff --raw are relative to the - # top-level of the repository, but we defer changing directories so - # that @ARGV can perform pathspec limiting in the current directory. - chdir($worktree); - - # Build index info for left and right sides of the diff - my $submodule_mode = '160000'; - my $symlink_mode = '120000'; - my $null_mode = '0' x 6; - my $null_sha1 = '0' x 40; - my $lindex = ''; - my $rindex = ''; - my $wtindex = ''; - my %submodule; - my %symlink; - my @files = (); - my %working_tree_dups = (); - my @rawdiff = split('\0', $diffrtn); - - my $i = 0; - while ($i < $#rawdiff) { - if ($rawdiff[$i] =~ /^::/) { - warn __ <<'EOF'; -Combined diff formats ('-c' and '--cc') are not supported in -directory diff mode ('-d' and '--dir-diff'). -EOF - exit(1); - } - - my ($lmode, $rmode, $lsha1, $rsha1, $status) = - split(' ', substr($rawdiff[$i], 1)); - my $src_path = $rawdiff[$i + 1]; - my $dst_path; - - if ($status =~ /^[CR]/) { - $dst_path = $rawdiff[$i + 2]; - $i += 3; - } else { - $dst_path = $src_path; - $i += 2; - } - - if ($lmode eq $submodule_mode or $rmode eq $submodule_mode) { - $submodule{$src_path}{left} = $lsha1; - if ($lsha1 ne $rsha1) { - $submodule{$dst_path}{right} = $rsha1; - } else { - $submodule{$dst_path}{right} = "$rsha1-dirty"; - } - next; - } - - if ($lmode eq $symlink_mode) { - $symlink{$src_path}{left} = - Git::command_oneline('show', $lsha1); - } - - if ($rmode eq $symlink_mode) { - $symlink{$dst_path}{right} = - Git::command_oneline('show', $rsha1); - } - - if ($lmode ne $null_mode and $status !~ /^C/) { - $lindex .= "$lmode $lsha1\t$src_path\0"; - } - - if ($rmode ne $null_mode) { - # Avoid duplicate entries - if ($working_tree_dups{$dst_path}++) { - next; - } - my ($use, $wt_sha1) = - use_wt_file($dst_path, $rsha1); - if ($use) { - push @files, $dst_path; - $wtindex .= "$rmode $wt_sha1\t$dst_path\0"; - } else { - $rindex .= "$rmode $rsha1\t$dst_path\0"; - } - } - } - - # Go to the root of the worktree so that the left index files - # are properly setup -- the index is toplevel-relative. - chdir($worktree); - - # Setup temp directories - my $tmpdir = tempdir('git-difftool.XXXXX', CLEANUP => 0, TMPDIR => 1); - my $ldir = "$tmpdir/left"; - my $rdir = "$tmpdir/right"; - mkpath($ldir) or exit_cleanup($tmpdir, 1); - mkpath($rdir) or exit_cleanup($tmpdir, 1); - - # Populate the left and right directories based on each index file - my ($inpipe, $ctx); - $ENV{GIT_INDEX_FILE} = "$tmpdir/lindex"; - ($inpipe, $ctx) = - Git::command_input_pipe('update-index', '-z', '--index-info'); - print($inpipe $lindex); - Git::command_close_pipe($inpipe, $ctx); - - my $rc = system('git', 'checkout-index', '--all', "--prefix=$ldir/"); - exit_cleanup($tmpdir, $rc) if $rc != 0; - - $ENV{GIT_INDEX_FILE} = "$tmpdir/rindex"; - ($inpipe, $ctx) = - Git::command_input_pipe('update-index', '-z', '--index-info'); - print($inpipe $rindex); - Git::command_close_pipe($inpipe, $ctx); - - $rc = system('git', 'checkout-index', '--all', "--prefix=$rdir/"); - exit_cleanup($tmpdir, $rc) if $rc != 0; - - $ENV{GIT_INDEX_FILE} = "$tmpdir/wtindex"; - ($inpipe, $ctx) = - Git::command_input_pipe('update-index', '--info-only', '-z', '--index-info'); - print($inpipe $wtindex); - Git::command_close_pipe($inpipe, $ctx); - - # If $GIT_DIR was explicitly set just for the update/checkout - # commands, then it should be unset before continuing. - delete($ENV{GIT_INDEX_FILE}); - - # Changes in the working tree need special treatment since they are - # not part of the index. - for my $file (@files) { - my $dir = dirname($file); - unless (-d "$rdir/$dir") { - mkpath("$rdir/$dir") or - exit_cleanup($tmpdir, 1); - } - if ($symlinks) { - symlink("$worktree/$file", "$rdir/$file") or - exit_cleanup($tmpdir, 1); - } else { - copy($file, "$rdir/$file") or - exit_cleanup($tmpdir, 1); - - my $mode = stat($file)->mode; - chmod($mode, "$rdir/$file") or - exit_cleanup($tmpdir, 1); - } - } - - # Changes to submodules require special treatment. This loop writes a - # temporary file to both the left and right directories to show the - # change in the recorded SHA1 for the submodule. - for my $path (keys %submodule) { - my $ok = 0; - if (defined($submodule{$path}{left})) { - $ok = write_to_file("$ldir/$path", - "Subproject commit $submodule{$path}{left}"); - } - if (defined($submodule{$path}{right})) { - $ok = write_to_file("$rdir/$path", - "Subproject commit $submodule{$path}{right}"); - } - exit_cleanup($tmpdir, 1) if not $ok; - } - - # Symbolic links require special treatment. The standard "git diff" - # shows only the link itself, not the contents of the link target. - # This loop replicates that behavior. - for my $path (keys %symlink) { - my $ok = 0; - if (defined($symlink{$path}{left})) { - $ok = write_to_file("$ldir/$path", - $symlink{$path}{left}); - } - if (defined($symlink{$path}{right})) { - $ok = write_to_file("$rdir/$path", - $symlink{$path}{right}); - } - exit_cleanup($tmpdir, 1) if not $ok; - } - - return ($ldir, $rdir, $tmpdir, @files); -} - -sub write_to_file -{ - my $path = shift; - my $value = shift; - - # Make sure the path to the file exists - my $dir = dirname($path); - unless (-d "$dir") { - mkpath("$dir") or return 0; - } - - # If the file already exists in that location, delete it. This - # is required in the case of symbolic links. - unlink($path); - - open(my $fh, '>', $path) or return 0; - print($fh $value); - close($fh); - - return 1; -} - -sub main -{ - # parse command-line options. all unrecognized options and arguments - # are passed through to the 'git diff' command. - my %opts = ( - difftool_cmd => undef, - dirdiff => undef, - extcmd => undef, - gui => undef, - help => undef, - prompt => undef, - symlinks => $^O ne 'cygwin' && - $^O ne 'MSWin32' && $^O ne 'msys', - tool_help => undef, - trust_exit_code => undef, - ); - GetOptions('g|gui!' => \$opts{gui}, - 'd|dir-diff' => \$opts{dirdiff}, - 'h' => \$opts{help}, - 'prompt!' => \$opts{prompt}, - 'y' => sub { $opts{prompt} = 0; }, - 'symlinks' => \$opts{symlinks}, - 'no-symlinks' => sub { $opts{symlinks} = 0; }, - 't|tool:s' => \$opts{difftool_cmd}, - 'tool-help' => \$opts{tool_help}, - 'trust-exit-code' => \$opts{trust_exit_code}, - 'no-trust-exit-code' => sub { $opts{trust_exit_code} = 0; }, - 'x|extcmd:s' => \$opts{extcmd}); - - if (defined($opts{help})) { - usage(0); - } - if (defined($opts{tool_help})) { - print_tool_help(); - } - if (defined($opts{difftool_cmd})) { - if (length($opts{difftool_cmd}) > 0) { - $ENV{GIT_DIFF_TOOL} = $opts{difftool_cmd}; - } else { - print __("No <tool> given for --tool=<tool>\n"); - usage(1); - } - } - if (defined($opts{extcmd})) { - if (length($opts{extcmd}) > 0) { - $ENV{GIT_DIFFTOOL_EXTCMD} = $opts{extcmd}; - } else { - print __("No <cmd> given for --extcmd=<cmd>\n"); - usage(1); - } - } - if ($opts{gui}) { - my $guitool = Git::config('diff.guitool'); - if (defined($guitool) && length($guitool) > 0) { - $ENV{GIT_DIFF_TOOL} = $guitool; - } - } - - if (!defined $opts{trust_exit_code}) { - $opts{trust_exit_code} = Git::config_bool('difftool.trustExitCode'); - } - if ($opts{trust_exit_code}) { - $ENV{GIT_DIFFTOOL_TRUST_EXIT_CODE} = 'true'; - } else { - $ENV{GIT_DIFFTOOL_TRUST_EXIT_CODE} = 'false'; - } - - # In directory diff mode, 'git-difftool--helper' is called once - # to compare the a/b directories. In file diff mode, 'git diff' - # will invoke a separate instance of 'git-difftool--helper' for - # each file that changed. - if (defined($opts{dirdiff})) { - dir_diff($opts{extcmd}, $opts{symlinks}); - } else { - file_diff($opts{prompt}); - } -} - -sub dir_diff -{ - my ($extcmd, $symlinks) = @_; - my $rc; - my $error = 0; - my $repo = Git->repository(); - my $repo_path = $repo->repo_path(); - my $worktree = $repo->wc_path(); - $worktree =~ s|/$||; # Avoid double slashes in symlink targets - my ($a, $b, $tmpdir, @files) = setup_dir_diff($worktree, $symlinks); - - if (defined($extcmd)) { - $rc = system($extcmd, $a, $b); - } else { - $ENV{GIT_DIFFTOOL_DIRDIFF} = 'true'; - $rc = system('git', 'difftool--helper', $a, $b); - } - # If the diff including working copy files and those - # files were modified during the diff, then the changes - # should be copied back to the working tree. - # Do not copy back files when symlinks are used and the - # external tool did not replace the original link with a file. - # - # These hashes are loaded lazily since they aren't needed - # in the common case of --symlinks and the difftool updating - # files through the symlink. - my %wt_modified; - my %tmp_modified; - my $indices_loaded = 0; - - for my $file (@files) { - next if $symlinks && -l "$b/$file"; - next if ! -f "$b/$file"; - - if (!$indices_loaded) { - %wt_modified = changed_files( - $repo_path, "$tmpdir/wtindex", $worktree); - %tmp_modified = changed_files( - $repo_path, "$tmpdir/wtindex", $b); - $indices_loaded = 1; - } - - if (exists $wt_modified{$file} and exists $tmp_modified{$file}) { - warn sprintf(__( - "warning: Both files modified:\n" . - "'%s/%s' and '%s/%s'.\n" . - "warning: Working tree file has been left.\n" . - "warning:\n"), $worktree, $file, $b, $file); - $error = 1; - } elsif (exists $tmp_modified{$file}) { - my $mode = stat("$b/$file")->mode; - copy("$b/$file", $file) or - exit_cleanup($tmpdir, 1); - - chmod($mode, $file) or - exit_cleanup($tmpdir, 1); - } - } - if ($error) { - warn sprintf(__( - "warning: Temporary files exist in '%s'.\n" . - "warning: You may want to cleanup or recover these.\n"), $tmpdir); - exit(1); - } else { - exit_cleanup($tmpdir, $rc); - } -} - -sub file_diff -{ - my ($prompt) = @_; - - if (defined($prompt)) { - if ($prompt) { - $ENV{GIT_DIFFTOOL_PROMPT} = 'true'; - } else { - $ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true'; - } - } - - $ENV{GIT_PAGER} = ''; - $ENV{GIT_EXTERNAL_DIFF} = 'git-difftool--helper'; - - # ActiveState Perl for Win32 does not implement POSIX semantics of - # exec* system call. It just spawns the given executable and finishes - # the starting program, exiting with code 0. - # system will at least catch the errors returned by git diff, - # allowing the caller of git difftool better handling of failures. - my $rc = system('git', 'diff', @ARGV); - exit($rc | ($rc >> 8)); -} - -main(); diff --git a/contrib/examples/git-fetch.sh b/contrib/examples/git-fetch.sh deleted file mode 100755 index 57d2e5616f..0000000000 --- a/contrib/examples/git-fetch.sh +++ /dev/null @@ -1,379 +0,0 @@ -#!/bin/sh -# - -USAGE='<fetch-options> <repository> <refspec>...' -SUBDIRECTORY_OK=Yes -. git-sh-setup -set_reflog_action "fetch $*" -cd_to_toplevel ;# probably unnecessary... - -. git-parse-remote -_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" - -LF=' -' -IFS="$LF" - -no_tags= -tags= -append= -force= -verbose= -update_head_ok= -exec= -keep= -shallow_depth= -no_progress= -test -t 1 || no_progress=--no-progress -quiet= -while test $# != 0 -do - case "$1" in - -a|--a|--ap|--app|--appe|--appen|--append) - append=t - ;; - --upl|--uplo|--uploa|--upload|--upload-|--upload-p|\ - --upload-pa|--upload-pac|--upload-pack) - shift - exec="--upload-pack=$1" - ;; - --upl=*|--uplo=*|--uploa=*|--upload=*|\ - --upload-=*|--upload-p=*|--upload-pa=*|--upload-pac=*|--upload-pack=*) - exec=--upload-pack=$(expr "z$1" : 'z-[^=]*=\(.*\)') - shift - ;; - -f|--f|--fo|--for|--forc|--force) - force=t - ;; - -t|--t|--ta|--tag|--tags) - tags=t - ;; - -n|--n|--no|--no-|--no-t|--no-ta|--no-tag|--no-tags) - no_tags=t - ;; - -u|--u|--up|--upd|--upda|--updat|--update|--update-|--update-h|\ - --update-he|--update-hea|--update-head|--update-head-|\ - --update-head-o|--update-head-ok) - update_head_ok=t - ;; - -q|--q|--qu|--qui|--quie|--quiet) - quiet=--quiet - ;; - -v|--verbose) - verbose="$verbose"Yes - ;; - -k|--k|--ke|--kee|--keep) - keep='-k -k' - ;; - --depth=*) - shallow_depth="--depth=$(expr "z$1" : 'z-[^=]*=\(.*\)')" - ;; - --depth) - shift - shallow_depth="--depth=$1" - ;; - -*) - usage - ;; - *) - break - ;; - esac - shift -done - -case "$#" in -0) - origin=$(get_default_remote) - test -n "$(get_remote_url ${origin})" || - die "Where do you want to fetch from today?" - set x $origin ; shift ;; -esac - -if test -z "$exec" -then - # No command line override and we have configuration for the remote. - exec="--upload-pack=$(get_uploadpack $1)" -fi - -remote_nick="$1" -remote=$(get_remote_url "$@") -refs= -rref= -rsync_slurped_objects= - -if test "" = "$append" -then - : >"$GIT_DIR/FETCH_HEAD" -fi - -# Global that is reused later -ls_remote_result=$(git ls-remote $exec "$remote") || - die "Cannot get the repository state from $remote" - -append_fetch_head () { - flags= - test -n "$verbose" && flags="$flags$LF-v" - test -n "$force$single_force" && flags="$flags$LF-f" - GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION" \ - git fetch--tool $flags append-fetch-head "$@" -} - -# updating the current HEAD with git-fetch in a bare -# repository is always fine. -if test -z "$update_head_ok" && test $(is_bare_repository) = false -then - orig_head=$(git rev-parse --verify HEAD 2>/dev/null) -fi - -# Allow --tags/--notags from remote.$1.tagopt -case "$tags$no_tags" in -'') - case "$(git config --get "remote.$1.tagopt")" in - --tags) - tags=t ;; - --no-tags) - no_tags=t ;; - esac -esac - -# If --tags (and later --heads or --all) is specified, then we are -# not talking about defaults stored in Pull: line of remotes or -# branches file, and just fetch those and refspecs explicitly given. -# Otherwise we do what we always did. - -reflist=$(get_remote_refs_for_fetch "$@") -if test "$tags" -then - taglist=$(IFS=' ' && - echo "$ls_remote_result" | - git show-ref --exclude-existing=refs/tags/ | - while read sha1 name - do - echo ".${name}:${name}" - done) || exit - if test "$#" -gt 1 - then - # remote URL plus explicit refspecs; we need to merge them. - reflist="$reflist$LF$taglist" - else - # No explicit refspecs; fetch tags only. - reflist=$taglist - fi -fi - -fetch_all_at_once () { - - eval=$(echo "$1" | git fetch--tool parse-reflist "-") - eval "$eval" - - ( : subshell because we muck with IFS - IFS=" $LF" - ( - if test "$remote" = . ; then - git show-ref $rref || echo failed "$remote" - elif test -f "$remote" ; then - test -n "$shallow_depth" && - die "shallow clone with bundle is not supported" - git bundle unbundle "$remote" $rref || - echo failed "$remote" - else - if test -d "$remote" && - - # The remote might be our alternate. With - # this optimization we will bypass fetch-pack - # altogether, which means we cannot be doing - # the shallow stuff at all. - test ! -f "$GIT_DIR/shallow" && - test -z "$shallow_depth" && - - # See if all of what we are going to fetch are - # connected to our repository's tips, in which - # case we do not have to do any fetch. - theirs=$(echo "$ls_remote_result" | \ - git fetch--tool -s pick-rref "$rref" "-") && - - # This will barf when $theirs reach an object that - # we do not have in our repository. Otherwise, - # we already have everything the fetch would bring in. - git rev-list --objects $theirs --not --all \ - >/dev/null 2>/dev/null - then - echo "$ls_remote_result" | \ - git fetch--tool pick-rref "$rref" "-" - else - flags= - case $verbose in - YesYes*) - flags="-v" - ;; - esac - git-fetch-pack --thin $exec $keep $shallow_depth \ - $quiet $no_progress $flags "$remote" $rref || - echo failed "$remote" - fi - fi - ) | - ( - flags= - test -n "$verbose" && flags="$flags -v" - test -n "$force" && flags="$flags -f" - GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION" \ - git fetch--tool $flags native-store \ - "$remote" "$remote_nick" "$refs" - ) - ) || exit - -} - -fetch_per_ref () { - reflist="$1" - refs= - rref= - - for ref in $reflist - do - refs="$refs$LF$ref" - - # These are relative path from $GIT_DIR, typically starting at refs/ - # but may be HEAD - if expr "z$ref" : 'z\.' >/dev/null - then - not_for_merge=t - ref=$(expr "z$ref" : 'z\.\(.*\)') - else - not_for_merge= - fi - if expr "z$ref" : 'z+' >/dev/null - then - single_force=t - ref=$(expr "z$ref" : 'z+\(.*\)') - else - single_force= - fi - remote_name=$(expr "z$ref" : 'z\([^:]*\):') - local_name=$(expr "z$ref" : 'z[^:]*:\(.*\)') - - rref="$rref$LF$remote_name" - - # There are transports that can fetch only one head at a time... - case "$remote" in - http://* | https://* | ftp://*) - test -n "$shallow_depth" && - die "shallow clone with http not supported" - proto=$(expr "$remote" : '\([^:]*\):') - if [ -n "$GIT_SSL_NO_VERIFY" ]; then - curl_extra_args="-k" - fi - if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \ - "$(git config --bool http.noEPSV)" = true ]; then - noepsv_opt="--disable-epsv" - fi - - # Find $remote_name from ls-remote output. - head=$(echo "$ls_remote_result" | \ - git fetch--tool -s pick-rref "$remote_name" "-") - expr "z$head" : "z$_x40\$" >/dev/null || - die "No such ref $remote_name at $remote" - echo >&2 "Fetching $remote_name from $remote using $proto" - case "$quiet" in '') v=-v ;; *) v= ;; esac - git-http-fetch $v -a "$head" "$remote" || exit - ;; - rsync://*) - test -n "$shallow_depth" && - die "shallow clone with rsync not supported" - TMP_HEAD="$GIT_DIR/TMP_HEAD" - rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1 - head=$(git rev-parse --verify TMP_HEAD) - rm -f "$TMP_HEAD" - case "$quiet" in '') v=-v ;; *) v= ;; esac - test "$rsync_slurped_objects" || { - rsync -a $v --ignore-existing --exclude info \ - "$remote/objects/" "$GIT_OBJECT_DIRECTORY/" || exit - - # Look at objects/info/alternates for rsync -- http will - # support it natively and git native ones will do it on - # the remote end. Not having that file is not a crime. - rsync -q "$remote/objects/info/alternates" \ - "$GIT_DIR/TMP_ALT" 2>/dev/null || - rm -f "$GIT_DIR/TMP_ALT" - if test -f "$GIT_DIR/TMP_ALT" - then - resolve_alternates "$remote" <"$GIT_DIR/TMP_ALT" | - while read alt - do - case "$alt" in 'bad alternate: '*) die "$alt";; esac - echo >&2 "Getting alternate: $alt" - rsync -av --ignore-existing --exclude info \ - "$alt" "$GIT_OBJECT_DIRECTORY/" || exit - done - rm -f "$GIT_DIR/TMP_ALT" - fi - rsync_slurped_objects=t - } - ;; - esac - - append_fetch_head "$head" "$remote" \ - "$remote_name" "$remote_nick" "$local_name" "$not_for_merge" || exit - - done - -} - -fetch_main () { - case "$remote" in - http://* | https://* | ftp://* | rsync://* ) - fetch_per_ref "$@" - ;; - *) - fetch_all_at_once "$@" - ;; - esac -} - -fetch_main "$reflist" || exit - -# automated tag following -case "$no_tags$tags" in -'') - case "$reflist" in - *:refs/*) - # effective only when we are following remote branch - # using local tracking branch. - taglist=$(IFS=' ' && - echo "$ls_remote_result" | - git show-ref --exclude-existing=refs/tags/ | - while read sha1 name - do - git cat-file -t "$sha1" >/dev/null 2>&1 || continue - echo >&2 "Auto-following $name" - echo ".${name}:${name}" - done) - esac - case "$taglist" in - '') ;; - ?*) - # do not deepen a shallow tree when following tags - shallow_depth= - fetch_main "$taglist" || exit ;; - esac -esac - -# If the original head was empty (i.e. no "master" yet), or -# if we were told not to worry, we do not have to check. -case "$orig_head" in -'') - ;; -?*) - curr_head=$(git rev-parse --verify HEAD 2>/dev/null) - if test "$curr_head" != "$orig_head" - then - git update-ref \ - -m "$GIT_REFLOG_ACTION: Undoing incorrectly fetched HEAD." \ - HEAD "$orig_head" - die "Cannot fetch into the current branch." - fi - ;; -esac diff --git a/contrib/examples/git-gc.sh b/contrib/examples/git-gc.sh deleted file mode 100755 index 1597e9f33f..0000000000 --- a/contrib/examples/git-gc.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2006, Shawn O. Pearce -# -# Cleanup unreachable files and optimize the repository. - -USAGE='[--prune]' -SUBDIRECTORY_OK=Yes -. git-sh-setup - -no_prune=: -while test $# != 0 -do - case "$1" in - --prune) - no_prune= - ;; - --) - usage - ;; - esac - shift -done - -case "$(git config --get gc.packrefs)" in -notbare|"") - test $(is_bare_repository) = true || pack_refs=true;; -*) - pack_refs=$(git config --bool --get gc.packrefs) -esac - -test "true" != "$pack_refs" || -git pack-refs --prune && -git reflog expire --all && -git-repack -a -d -l && -$no_prune git prune && -git rerere gc || exit diff --git a/contrib/examples/git-log.sh b/contrib/examples/git-log.sh deleted file mode 100755 index c2ea71cf14..0000000000 --- a/contrib/examples/git-log.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005 Linus Torvalds -# - -USAGE='[--max-count=<n>] [<since>..<limit>] [--pretty=<format>] [git-rev-list options]' -SUBDIRECTORY_OK='Yes' -. git-sh-setup - -revs=$(git-rev-parse --revs-only --no-flags --default HEAD "$@") || exit -[ "$revs" ] || { - die "No HEAD ref" -} -git-rev-list --pretty $(git-rev-parse --default HEAD "$@") | -LESS=-S ${PAGER:-less} diff --git a/contrib/examples/git-ls-remote.sh b/contrib/examples/git-ls-remote.sh deleted file mode 100755 index 2aa89a7df8..0000000000 --- a/contrib/examples/git-ls-remote.sh +++ /dev/null @@ -1,142 +0,0 @@ -#!/bin/sh -# - -usage () { - echo >&2 "usage: $0 [--heads] [--tags] [-u|--upload-pack <upload-pack>]" - echo >&2 " <repository> <refs>..." - exit 1; -} - -die () { - echo >&2 "$*" - exit 1 -} - -exec= -while test $# != 0 -do - case "$1" in - -h|--h|--he|--hea|--head|--heads) - heads=heads; shift ;; - -t|--t|--ta|--tag|--tags) - tags=tags; shift ;; - -u|--u|--up|--upl|--uploa|--upload|--upload-|--upload-p|--upload-pa|\ - --upload-pac|--upload-pack) - shift - exec="--upload-pack=$1" - shift;; - -u=*|--u=*|--up=*|--upl=*|--uplo=*|--uploa=*|--upload=*|\ - --upload-=*|--upload-p=*|--upload-pa=*|--upload-pac=*|--upload-pack=*) - exec=--upload-pack=$(expr "z$1" : 'z-[^=]*=\(.*\)') - shift;; - --) - shift; break ;; - -*) - usage ;; - *) - break ;; - esac -done - -case "$#" in 0) usage ;; esac - -case ",$heads,$tags," in -,,,) heads=heads tags=tags other=other ;; -esac - -. git-parse-remote -peek_repo="$(get_remote_url "$@")" -shift - -tmp=.ls-remote-$$ -trap "rm -fr $tmp-*" 0 1 2 3 15 -tmpdir=$tmp-d - -case "$peek_repo" in -http://* | https://* | ftp://* ) - if [ -n "$GIT_SSL_NO_VERIFY" -o \ - "$(git config --bool http.sslVerify)" = false ]; then - curl_extra_args="-k" - fi - if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \ - "$(git config --bool http.noEPSV)" = true ]; then - curl_extra_args="${curl_extra_args} --disable-epsv" - fi - curl -nsf $curl_extra_args --header "Pragma: no-cache" "$peek_repo/info/refs" || - echo "failed slurping" - ;; - -rsync://* ) - mkdir $tmpdir && - rsync -rlq "$peek_repo/HEAD" $tmpdir && - rsync -rq "$peek_repo/refs" $tmpdir || { - echo "failed slurping" - exit - } - head=$(cat "$tmpdir/HEAD") && - case "$head" in - ref:' '*) - head=$(expr "z$head" : 'zref: \(.*\)') && - head=$(cat "$tmpdir/$head") || exit - esac && - echo "$head HEAD" - (cd $tmpdir && find refs -type f) | - while read path - do - tr -d '\012' <"$tmpdir/$path" - echo " $path" - done && - rm -fr $tmpdir - ;; - -* ) - if test -f "$peek_repo" ; then - git bundle list-heads "$peek_repo" || - echo "failed slurping" - else - git-peek-remote $exec "$peek_repo" || - echo "failed slurping" - fi - ;; -esac | -sort -t ' ' -k 2 | -while read sha1 path -do - case "$sha1" in - failed) - exit 1 ;; - esac - case "$path" in - refs/heads/*) - group=heads ;; - refs/tags/*) - group=tags ;; - *) - group=other ;; - esac - case ",$heads,$tags,$other," in - *,$group,*) - ;; - *) - continue;; - esac - case "$#" in - 0) - match=yes ;; - *) - match=no - for pat - do - case "/$path" in - */$pat ) - match=yes - break ;; - esac - done - esac - case "$match" in - no) - continue ;; - esac - echo "$sha1 $path" -done diff --git a/contrib/examples/git-merge-ours.sh b/contrib/examples/git-merge-ours.sh deleted file mode 100755 index 29dba4ba3a..0000000000 --- a/contrib/examples/git-merge-ours.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005 Junio C Hamano -# -# Pretend we resolved the heads, but declare our tree trumps everybody else. -# - -# We need to exit with 2 if the index does not match our HEAD tree, -# because the current index is what we will be committing as the -# merge result. - -git diff-index --quiet --cached HEAD -- || exit 2 - -exit 0 diff --git a/contrib/examples/git-merge.sh b/contrib/examples/git-merge.sh deleted file mode 100755 index 932e78dbfe..0000000000 --- a/contrib/examples/git-merge.sh +++ /dev/null @@ -1,620 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005 Junio C Hamano -# - -OPTIONS_KEEPDASHDASH= -OPTIONS_SPEC="\ -git merge [options] <remote>... -git merge [options] <msg> HEAD <remote> --- -stat show a diffstat at the end of the merge -n don't show a diffstat at the end of the merge -summary (synonym to --stat) -log add list of one-line log to merge commit message -squash create a single commit instead of doing a merge -commit perform a commit if the merge succeeds (default) -ff allow fast-forward (default) -ff-only abort if fast-forward is not possible -rerere-autoupdate update index with any reused conflict resolution -s,strategy= merge strategy to use -X= option for selected merge strategy -m,message= message to be used for the merge commit (if any) -" - -SUBDIRECTORY_OK=Yes -. git-sh-setup -require_work_tree -cd_to_toplevel - -test -z "$(git ls-files -u)" || - die "Merge is not possible because you have unmerged files." - -! test -e "$GIT_DIR/MERGE_HEAD" || - die 'You have not concluded your merge (MERGE_HEAD exists).' - -LF=' -' - -all_strategies='recur recursive octopus resolve stupid ours subtree' -all_strategies="$all_strategies recursive-ours recursive-theirs" -not_strategies='base file index tree' -default_twohead_strategies='recursive' -default_octopus_strategies='octopus' -no_fast_forward_strategies='subtree ours' -no_trivial_strategies='recursive recur subtree ours recursive-ours recursive-theirs' -use_strategies= -xopt= - -allow_fast_forward=t -fast_forward_only= -allow_trivial_merge=t -squash= no_commit= log_arg= rr_arg= - -dropsave() { - rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" \ - "$GIT_DIR/MERGE_STASH" "$GIT_DIR/MERGE_MODE" || exit 1 -} - -savestate() { - # Stash away any local modifications. - git stash create >"$GIT_DIR/MERGE_STASH" -} - -restorestate() { - if test -f "$GIT_DIR/MERGE_STASH" - then - git reset --hard $head >/dev/null - git stash apply $(cat "$GIT_DIR/MERGE_STASH") - git update-index --refresh >/dev/null - fi -} - -finish_up_to_date () { - case "$squash" in - t) - echo "$1 (nothing to squash)" ;; - '') - echo "$1" ;; - esac - dropsave -} - -squash_message () { - echo Squashed commit of the following: - echo - git log --no-merges --pretty=medium ^"$head" $remoteheads -} - -finish () { - if test '' = "$2" - then - rlogm="$GIT_REFLOG_ACTION" - else - echo "$2" - rlogm="$GIT_REFLOG_ACTION: $2" - fi - case "$squash" in - t) - echo "Squash commit -- not updating HEAD" - squash_message >"$GIT_DIR/SQUASH_MSG" - ;; - '') - case "$merge_msg" in - '') - echo "No merge message -- not updating HEAD" - ;; - *) - git update-ref -m "$rlogm" HEAD "$1" "$head" || exit 1 - git gc --auto - ;; - esac - ;; - esac - case "$1" in - '') - ;; - ?*) - if test "$show_diffstat" = t - then - # We want color (if set), but no pager - GIT_PAGER='' git diff --stat --summary -M "$head" "$1" - fi - ;; - esac - - # Run a post-merge hook - if test -x "$GIT_DIR"/hooks/post-merge - then - case "$squash" in - t) - "$GIT_DIR"/hooks/post-merge 1 - ;; - '') - "$GIT_DIR"/hooks/post-merge 0 - ;; - esac - fi -} - -merge_name () { - remote="$1" - rh=$(git rev-parse --verify "$remote^0" 2>/dev/null) || return - if truname=$(expr "$remote" : '\(.*\)~[0-9]*$') && - git show-ref -q --verify "refs/heads/$truname" 2>/dev/null - then - echo "$rh branch '$truname' (early part) of ." - return - fi - if found_ref=$(git rev-parse --symbolic-full-name --verify \ - "$remote" 2>/dev/null) - then - expanded=$(git check-ref-format --branch "$remote") || - exit - if test "${found_ref#refs/heads/}" != "$found_ref" - then - echo "$rh branch '$expanded' of ." - return - elif test "${found_ref#refs/remotes/}" != "$found_ref" - then - echo "$rh remote branch '$expanded' of ." - return - fi - fi - if test "$remote" = "FETCH_HEAD" && test -r "$GIT_DIR/FETCH_HEAD" - then - sed -e 's/ not-for-merge / /' -e 1q \ - "$GIT_DIR/FETCH_HEAD" - return - fi - echo "$rh commit '$remote'" -} - -parse_config () { - while test $# != 0; do - case "$1" in - -n|--no-stat|--no-summary) - show_diffstat=false ;; - --stat|--summary) - show_diffstat=t ;; - --log|--no-log) - log_arg=$1 ;; - --squash) - test "$allow_fast_forward" = t || - die "You cannot combine --squash with --no-ff." - squash=t no_commit=t ;; - --no-squash) - squash= no_commit= ;; - --commit) - no_commit= ;; - --no-commit) - no_commit=t ;; - --ff) - allow_fast_forward=t ;; - --no-ff) - test "$squash" != t || - die "You cannot combine --squash with --no-ff." - test "$fast_forward_only" != t || - die "You cannot combine --ff-only with --no-ff." - allow_fast_forward=f ;; - --ff-only) - test "$allow_fast_forward" != f || - die "You cannot combine --ff-only with --no-ff." - fast_forward_only=t ;; - --rerere-autoupdate|--no-rerere-autoupdate) - rr_arg=$1 ;; - -s|--strategy) - shift - case " $all_strategies " in - *" $1 "*) - use_strategies="$use_strategies$1 " - ;; - *) - case " $not_strategies " in - *" $1 "*) - false - esac && - type "git-merge-$1" >/dev/null 2>&1 || - die "available strategies are: $all_strategies" - use_strategies="$use_strategies$1 " - ;; - esac - ;; - -X) - shift - xopt="${xopt:+$xopt }$(git rev-parse --sq-quote "--$1")" - ;; - -m|--message) - shift - merge_msg="$1" - have_message=t - ;; - --) - shift - break ;; - *) usage ;; - esac - shift - done - args_left=$# -} - -test $# != 0 || usage - -have_message= - -if branch=$(git-symbolic-ref -q HEAD) -then - mergeopts=$(git config "branch.${branch#refs/heads/}.mergeoptions") - if test -n "$mergeopts" - then - parse_config $mergeopts -- - fi -fi - -parse_config "$@" -while test $args_left -lt $#; do shift; done - -if test -z "$show_diffstat"; then - test "$(git config --bool merge.diffstat)" = false && show_diffstat=false - test "$(git config --bool merge.stat)" = false && show_diffstat=false - test -z "$show_diffstat" && show_diffstat=t -fi - -# This could be traditional "merge <msg> HEAD <commit>..." and the -# way we can tell it is to see if the second token is HEAD, but some -# people might have misused the interface and used a commit-ish that -# is the same as HEAD there instead. Traditional format never would -# have "-m" so it is an additional safety measure to check for it. - -if test -z "$have_message" && - second_token=$(git rev-parse --verify "$2^0" 2>/dev/null) && - head_commit=$(git rev-parse --verify "HEAD" 2>/dev/null) && - test "$second_token" = "$head_commit" -then - merge_msg="$1" - shift - head_arg="$1" - shift -elif ! git rev-parse --verify HEAD >/dev/null 2>&1 -then - # If the merged head is a valid one there is no reason to - # forbid "git merge" into a branch yet to be born. We do - # the same for "git pull". - if test 1 -ne $# - then - echo >&2 "Can merge only exactly one commit into empty head" - exit 1 - fi - - test "$squash" != t || - die "Squash commit into empty head not supported yet" - test "$allow_fast_forward" = t || - die "Non-fast-forward into an empty head does not make sense" - rh=$(git rev-parse --verify "$1^0") || - die "$1 - not something we can merge" - - git update-ref -m "initial pull" HEAD "$rh" "" && - git read-tree --reset -u HEAD - exit - -else - # We are invoked directly as the first-class UI. - head_arg=HEAD - - # All the rest are the commits being merged; prepare - # the standard merge summary message to be appended to - # the given message. If remote is invalid we will die - # later in the common codepath so we discard the error - # in this loop. - merge_msg="$( - for remote - do - merge_name "$remote" - done | - if test "$have_message" = t - then - git fmt-merge-msg -m "$merge_msg" $log_arg - else - git fmt-merge-msg $log_arg - fi - )" -fi -head=$(git rev-parse --verify "$head_arg"^0) || usage - -# All the rest are remote heads -test "$#" = 0 && usage ;# we need at least one remote head. -set_reflog_action "merge $*" - -remoteheads= -for remote -do - remotehead=$(git rev-parse --verify "$remote"^0 2>/dev/null) || - die "$remote - not something we can merge" - remoteheads="${remoteheads}$remotehead " - eval GITHEAD_$remotehead='"$remote"' - export GITHEAD_$remotehead -done -set x $remoteheads ; shift - -case "$use_strategies" in -'') - case "$#" in - 1) - var="$(git config --get pull.twohead)" - if test -n "$var" - then - use_strategies="$var" - else - use_strategies="$default_twohead_strategies" - fi ;; - *) - var="$(git config --get pull.octopus)" - if test -n "$var" - then - use_strategies="$var" - else - use_strategies="$default_octopus_strategies" - fi ;; - esac - ;; -esac - -for s in $use_strategies -do - for ss in $no_fast_forward_strategies - do - case " $s " in - *" $ss "*) - allow_fast_forward=f - break - ;; - esac - done - for ss in $no_trivial_strategies - do - case " $s " in - *" $ss "*) - allow_trivial_merge=f - break - ;; - esac - done -done - -case "$#" in -1) - common=$(git merge-base --all $head "$@") - ;; -*) - common=$(git merge-base --all --octopus $head "$@") - ;; -esac -echo "$head" >"$GIT_DIR/ORIG_HEAD" - -case "$allow_fast_forward,$#,$common,$no_commit" in -?,*,'',*) - # No common ancestors found. We need a real merge. - ;; -?,1,"$1",*) - # If head can reach all the merge then we are up to date. - # but first the most common case of merging one remote. - finish_up_to_date "Already up to date." - exit 0 - ;; -t,1,"$head",*) - # Again the most common case of merging one remote. - echo "Updating $(git rev-parse --short $head)..$(git rev-parse --short $1)" - git update-index --refresh 2>/dev/null - msg="Fast-forward" - if test -n "$have_message" - then - msg="$msg (no commit created; -m option ignored)" - fi - new_head=$(git rev-parse --verify "$1^0") && - git read-tree -v -m -u --exclude-per-directory=.gitignore $head "$new_head" && - finish "$new_head" "$msg" || exit - dropsave - exit 0 - ;; -?,1,?*"$LF"?*,*) - # We are not doing octopus and not fast-forward. Need a - # real merge. - ;; -?,1,*,) - # We are not doing octopus, not fast-forward, and have only - # one common. - git update-index --refresh 2>/dev/null - case "$allow_trivial_merge,$fast_forward_only" in - t,) - # See if it is really trivial. - git var GIT_COMMITTER_IDENT >/dev/null || exit - echo "Trying really trivial in-index merge..." - if git read-tree --trivial -m -u -v $common $head "$1" && - result_tree=$(git write-tree) - then - echo "Wonderful." - result_commit=$( - printf '%s\n' "$merge_msg" | - git commit-tree $result_tree -p HEAD -p "$1" - ) || exit - finish "$result_commit" "In-index merge" - dropsave - exit 0 - fi - echo "Nope." - esac - ;; -*) - # An octopus. If we can reach all the remote we are up to date. - up_to_date=t - for remote - do - common_one=$(git merge-base --all $head $remote) - if test "$common_one" != "$remote" - then - up_to_date=f - break - fi - done - if test "$up_to_date" = t - then - finish_up_to_date "Already up to date. Yeeah!" - exit 0 - fi - ;; -esac - -if test "$fast_forward_only" = t -then - die "Not possible to fast-forward, aborting." -fi - -# We are going to make a new commit. -git var GIT_COMMITTER_IDENT >/dev/null || exit - -# At this point, we need a real merge. No matter what strategy -# we use, it would operate on the index, possibly affecting the -# working tree, and when resolved cleanly, have the desired tree -# in the index -- this means that the index must be in sync with -# the $head commit. The strategies are responsible to ensure this. - -case "$use_strategies" in -?*' '?*) - # Stash away the local changes so that we can try more than one. - savestate - single_strategy=no - ;; -*) - rm -f "$GIT_DIR/MERGE_STASH" - single_strategy=yes - ;; -esac - -result_tree= best_cnt=-1 best_strategy= wt_strategy= -merge_was_ok= -for strategy in $use_strategies -do - test "$wt_strategy" = '' || { - echo "Rewinding the tree to pristine..." - restorestate - } - case "$single_strategy" in - no) - echo "Trying merge strategy $strategy..." - ;; - esac - - # Remember which strategy left the state in the working tree - wt_strategy=$strategy - - eval 'git-merge-$strategy '"$xopt"' $common -- "$head_arg" "$@"' - exit=$? - if test "$no_commit" = t && test "$exit" = 0 - then - merge_was_ok=t - exit=1 ;# pretend it left conflicts. - fi - - test "$exit" = 0 || { - - # The backend exits with 1 when conflicts are left to be resolved, - # with 2 when it does not handle the given merge at all. - - if test "$exit" -eq 1 - then - cnt=$({ - git diff-files --name-only - git ls-files --unmerged - } | wc -l) - if test $best_cnt -le 0 || test $cnt -le $best_cnt - then - best_strategy=$strategy - best_cnt=$cnt - fi - fi - continue - } - - # Automerge succeeded. - result_tree=$(git write-tree) && break -done - -# If we have a resulting tree, that means the strategy module -# auto resolved the merge cleanly. -if test '' != "$result_tree" -then - if test "$allow_fast_forward" = "t" - then - parents=$(git merge-base --independent "$head" "$@") - else - parents=$(git rev-parse "$head" "$@") - fi - parents=$(echo "$parents" | sed -e 's/^/-p /') - result_commit=$(printf '%s\n' "$merge_msg" | git commit-tree $result_tree $parents) || exit - finish "$result_commit" "Merge made by $wt_strategy." - dropsave - exit 0 -fi - -# Pick the result from the best strategy and have the user fix it up. -case "$best_strategy" in -'') - restorestate - case "$use_strategies" in - ?*' '?*) - echo >&2 "No merge strategy handled the merge." - ;; - *) - echo >&2 "Merge with strategy $use_strategies failed." - ;; - esac - exit 2 - ;; -"$wt_strategy") - # We already have its result in the working tree. - ;; -*) - echo "Rewinding the tree to pristine..." - restorestate - echo "Using the $best_strategy to prepare resolving by hand." - git-merge-$best_strategy $common -- "$head_arg" "$@" - ;; -esac - -if test "$squash" = t -then - finish -else - for remote - do - echo $remote - done >"$GIT_DIR/MERGE_HEAD" - printf '%s\n' "$merge_msg" >"$GIT_DIR/MERGE_MSG" || - die "Could not write to $GIT_DIR/MERGE_MSG" - if test "$allow_fast_forward" != t - then - printf "%s" no-ff - else - : - fi >"$GIT_DIR/MERGE_MODE" || - die "Could not write to $GIT_DIR/MERGE_MODE" -fi - -if test "$merge_was_ok" = t -then - echo >&2 \ - "Automatic merge went well; stopped before committing as requested" - exit 0 -else - { - echo ' -Conflicts: -' - git ls-files --unmerged | - sed -e 's/^[^ ]* / /' | - uniq - } >>"$GIT_DIR/MERGE_MSG" - git rerere $rr_arg - die "Automatic merge failed; fix conflicts and then commit the result." -fi diff --git a/contrib/examples/git-notes.sh b/contrib/examples/git-notes.sh deleted file mode 100755 index e642e47d9f..0000000000 --- a/contrib/examples/git-notes.sh +++ /dev/null @@ -1,121 +0,0 @@ -#!/bin/sh - -USAGE="(edit [-F <file> | -m <msg>] | show) [commit]" -. git-sh-setup - -test -z "$1" && usage -ACTION="$1"; shift - -test -z "$GIT_NOTES_REF" && GIT_NOTES_REF="$(git config core.notesref)" -test -z "$GIT_NOTES_REF" && GIT_NOTES_REF="refs/notes/commits" - -MESSAGE= -while test $# != 0 -do - case "$1" in - -m) - test "$ACTION" = "edit" || usage - shift - if test "$#" = "0"; then - die "error: option -m needs an argument" - else - if [ -z "$MESSAGE" ]; then - MESSAGE="$1" - else - MESSAGE="$MESSAGE - -$1" - fi - shift - fi - ;; - -F) - test "$ACTION" = "edit" || usage - shift - if test "$#" = "0"; then - die "error: option -F needs an argument" - else - if [ -z "$MESSAGE" ]; then - MESSAGE="$(cat "$1")" - else - MESSAGE="$MESSAGE - -$(cat "$1")" - fi - shift - fi - ;; - -*) - usage - ;; - *) - break - ;; - esac -done - -COMMIT=$(git rev-parse --verify --default HEAD "$@") || -die "Invalid commit: $@" - -case "$ACTION" in -edit) - if [ "${GIT_NOTES_REF#refs/notes/}" = "$GIT_NOTES_REF" ]; then - die "Refusing to edit notes in $GIT_NOTES_REF (outside of refs/notes/)" - fi - - MSG_FILE="$GIT_DIR/new-notes-$COMMIT" - GIT_INDEX_FILE="$MSG_FILE.idx" - export GIT_INDEX_FILE - - trap ' - test -f "$MSG_FILE" && rm "$MSG_FILE" - test -f "$GIT_INDEX_FILE" && rm "$GIT_INDEX_FILE" - ' 0 - - CURRENT_HEAD=$(git show-ref "$GIT_NOTES_REF" | cut -f 1 -d ' ') - if [ -z "$CURRENT_HEAD" ]; then - PARENT= - else - PARENT="-p $CURRENT_HEAD" - git read-tree "$GIT_NOTES_REF" || die "Could not read index" - fi - - if [ -z "$MESSAGE" ]; then - GIT_NOTES_REF= git log -1 $COMMIT | sed "s/^/#/" > "$MSG_FILE" - if [ ! -z "$CURRENT_HEAD" ]; then - git cat-file blob :$COMMIT >> "$MSG_FILE" 2> /dev/null - fi - core_editor="$(git config core.editor)" - ${GIT_EDITOR:-${core_editor:-${VISUAL:-${EDITOR:-vi}}}} "$MSG_FILE" - else - echo "$MESSAGE" > "$MSG_FILE" - fi - - grep -v ^# < "$MSG_FILE" | git stripspace > "$MSG_FILE".processed - mv "$MSG_FILE".processed "$MSG_FILE" - if [ -s "$MSG_FILE" ]; then - BLOB=$(git hash-object -w "$MSG_FILE") || - die "Could not write into object database" - git update-index --add --cacheinfo 0644 $BLOB $COMMIT || - die "Could not write index" - else - test -z "$CURRENT_HEAD" && - die "Will not initialise with empty tree" - git update-index --force-remove $COMMIT || - die "Could not update index" - fi - - TREE=$(git write-tree) || die "Could not write tree" - NEW_HEAD=$(echo Annotate $COMMIT | git commit-tree $TREE $PARENT) || - die "Could not annotate" - git update-ref -m "Annotate $COMMIT" \ - "$GIT_NOTES_REF" $NEW_HEAD $CURRENT_HEAD -;; -show) - git rev-parse -q --verify "$GIT_NOTES_REF":$COMMIT > /dev/null || - die "No note for commit $COMMIT." - git show "$GIT_NOTES_REF":$COMMIT -;; -*) - usage -esac diff --git a/contrib/examples/git-pull.sh b/contrib/examples/git-pull.sh deleted file mode 100755 index 6b3a03f9b0..0000000000 --- a/contrib/examples/git-pull.sh +++ /dev/null @@ -1,381 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005 Junio C Hamano -# -# Fetch one or more remote refs and merge it/them into the current HEAD. - -SUBDIRECTORY_OK=Yes -OPTIONS_KEEPDASHDASH= -OPTIONS_STUCKLONG=Yes -OPTIONS_SPEC="\ -git pull [options] [<repository> [<refspec>...]] - -Fetch one or more remote refs and integrate it/them with the current HEAD. --- -v,verbose be more verbose -q,quiet be more quiet -progress force progress reporting - - Options related to merging -r,rebase?false|true|preserve incorporate changes by rebasing rather than merging -n! do not show a diffstat at the end of the merge -stat show a diffstat at the end of the merge -summary (synonym to --stat) -log?n add (at most <n>) entries from shortlog to merge commit message -squash create a single commit instead of doing a merge -commit perform a commit if the merge succeeds (default) -e,edit edit message before committing -ff allow fast-forward -ff-only! abort if fast-forward is not possible -verify-signatures verify that the named commit has a valid GPG signature -s,strategy=strategy merge strategy to use -X,strategy-option=option option for selected merge strategy -S,gpg-sign?key-id GPG sign commit - - Options related to fetching -all fetch from all remotes -a,append append to .git/FETCH_HEAD instead of overwriting -upload-pack=path path to upload pack on remote end -f,force force overwrite of local branch -t,tags fetch all tags and associated objects -p,prune prune remote-tracking branches no longer on remote -recurse-submodules?on-demand control recursive fetching of submodules -dry-run dry run -k,keep keep downloaded pack -depth=depth deepen history of shallow clone -unshallow convert to a complete repository -update-shallow accept refs that update .git/shallow -refmap=refmap specify fetch refmap -" -test $# -gt 0 && args="$*" -. git-sh-setup -. git-sh-i18n -set_reflog_action "pull${args+ $args}" -require_work_tree_exists -cd_to_toplevel - - -die_conflict () { - git diff-index --cached --name-status -r --ignore-submodules HEAD -- - if [ $(git config --bool --get advice.resolveConflict || echo true) = "true" ]; then - die "$(gettext "Pull is not possible because you have unmerged files. -Please, fix them up in the work tree, and then use 'git add/rm <file>' -as appropriate to mark resolution and make a commit.")" - else - die "$(gettext "Pull is not possible because you have unmerged files.")" - fi -} - -die_merge () { - if [ $(git config --bool --get advice.resolveConflict || echo true) = "true" ]; then - die "$(gettext "You have not concluded your merge (MERGE_HEAD exists). -Please, commit your changes before merging.")" - else - die "$(gettext "You have not concluded your merge (MERGE_HEAD exists).")" - fi -} - -test -z "$(git ls-files -u)" || die_conflict -test -f "$GIT_DIR/MERGE_HEAD" && die_merge - -bool_or_string_config () { - git config --bool "$1" 2>/dev/null || git config "$1" -} - -strategy_args= diffstat= no_commit= squash= no_ff= ff_only= -log_arg= verbosity= progress= recurse_submodules= verify_signatures= -merge_args= edit= rebase_args= all= append= upload_pack= force= tags= prune= -keep= depth= unshallow= update_shallow= refmap= -curr_branch=$(git symbolic-ref -q HEAD) -curr_branch_short="${curr_branch#refs/heads/}" -rebase=$(bool_or_string_config branch.$curr_branch_short.rebase) -if test -z "$rebase" -then - rebase=$(bool_or_string_config pull.rebase) -fi - -# Setup default fast-forward options via `pull.ff` -pull_ff=$(bool_or_string_config pull.ff) -case "$pull_ff" in -true) - no_ff=--ff - ;; -false) - no_ff=--no-ff - ;; -only) - ff_only=--ff-only - ;; -esac - - -dry_run= -while : -do - case "$1" in - -q|--quiet) - verbosity="$verbosity -q" ;; - -v|--verbose) - verbosity="$verbosity -v" ;; - --progress) - progress=--progress ;; - --no-progress) - progress=--no-progress ;; - -n|--no-stat|--no-summary) - diffstat=--no-stat ;; - --stat|--summary) - diffstat=--stat ;; - --log|--log=*|--no-log) - log_arg="$1" ;; - --no-commit) - no_commit=--no-commit ;; - --commit) - no_commit=--commit ;; - -e|--edit) - edit=--edit ;; - --no-edit) - edit=--no-edit ;; - --squash) - squash=--squash ;; - --no-squash) - squash=--no-squash ;; - --ff) - no_ff=--ff ;; - --no-ff) - no_ff=--no-ff ;; - --ff-only) - ff_only=--ff-only ;; - -s*|--strategy=*) - strategy_args="$strategy_args $1" - ;; - -X*|--strategy-option=*) - merge_args="$merge_args $(git rev-parse --sq-quote "$1")" - ;; - -r*|--rebase=*) - rebase="${1#*=}" - ;; - --rebase) - rebase=true - ;; - --no-rebase) - rebase=false - ;; - --recurse-submodules) - recurse_submodules=--recurse-submodules - ;; - --recurse-submodules=*) - recurse_submodules="$1" - ;; - --no-recurse-submodules) - recurse_submodules=--no-recurse-submodules - ;; - --verify-signatures) - verify_signatures=--verify-signatures - ;; - --no-verify-signatures) - verify_signatures=--no-verify-signatures - ;; - --gpg-sign|-S) - gpg_sign_args=-S - ;; - --gpg-sign=*) - gpg_sign_args=$(git rev-parse --sq-quote "-S${1#--gpg-sign=}") - ;; - -S*) - gpg_sign_args=$(git rev-parse --sq-quote "$1") - ;; - --dry-run) - dry_run=--dry-run - ;; - --all|--no-all) - all=$1 ;; - -a|--append|--no-append) - append=$1 ;; - --upload-pack=*|--no-upload-pack) - upload_pack=$1 ;; - -f|--force|--no-force) - force="$force $1" ;; - -t|--tags|--no-tags) - tags=$1 ;; - -p|--prune|--no-prune) - prune=$1 ;; - -k|--keep|--no-keep) - keep=$1 ;; - --depth=*|--no-depth) - depth=$1 ;; - --unshallow|--no-unshallow) - unshallow=$1 ;; - --update-shallow|--no-update-shallow) - update_shallow=$1 ;; - --refmap=*|--no-refmap) - refmap=$1 ;; - -h|--help-all) - usage - ;; - --) - shift - break - ;; - *) - usage - ;; - esac - shift -done - -case "$rebase" in -preserve) - rebase=true - rebase_args=--preserve-merges - ;; -true|false|'') - ;; -*) - echo "Invalid value for --rebase, should be true, false, or preserve" - usage - exit 1 - ;; -esac - -error_on_no_merge_candidates () { - exec >&2 - - if test true = "$rebase" - then - op_type=rebase - op_prep=against - else - op_type=merge - op_prep=with - fi - - upstream=$(git config "branch.$curr_branch_short.merge") - remote=$(git config "branch.$curr_branch_short.remote") - - if [ $# -gt 1 ]; then - if [ "$rebase" = true ]; then - printf "There is no candidate for rebasing against " - else - printf "There are no candidates for merging " - fi - echo "among the refs that you just fetched." - echo "Generally this means that you provided a wildcard refspec which had no" - echo "matches on the remote end." - elif [ $# -gt 0 ] && [ "$1" != "$remote" ]; then - echo "You asked to pull from the remote '$1', but did not specify" - echo "a branch. Because this is not the default configured remote" - echo "for your current branch, you must specify a branch on the command line." - elif [ -z "$curr_branch" -o -z "$upstream" ]; then - . git-parse-remote - error_on_missing_default_upstream "pull" $op_type $op_prep \ - "git pull <remote> <branch>" - else - echo "Your configuration specifies to $op_type $op_prep the ref '${upstream#refs/heads/}'" - echo "from the remote, but no such ref was fetched." - fi - exit 1 -} - -test true = "$rebase" && { - if ! git rev-parse -q --verify HEAD >/dev/null - then - # On an unborn branch - if test -f "$(git rev-parse --git-path index)" - then - die "$(gettext "updating an unborn branch with changes added to the index")" - fi - else - require_clean_work_tree "pull with rebase" "Please commit or stash them." - fi - oldremoteref= && - test -n "$curr_branch" && - . git-parse-remote && - remoteref="$(get_remote_merge_branch "$@" 2>/dev/null)" && - oldremoteref=$(git merge-base --fork-point "$remoteref" $curr_branch 2>/dev/null) -} -orig_head=$(git rev-parse -q --verify HEAD) -git fetch $verbosity $progress $dry_run $recurse_submodules $all $append \ -${upload_pack:+"$upload_pack"} $force $tags $prune $keep $depth $unshallow $update_shallow \ -$refmap --update-head-ok "$@" || exit 1 -test -z "$dry_run" || exit 0 - -curr_head=$(git rev-parse -q --verify HEAD) -if test -n "$orig_head" && test "$curr_head" != "$orig_head" -then - # The fetch involved updating the current branch. - - # The working tree and the index file is still based on the - # $orig_head commit, but we are merging into $curr_head. - # First update the working tree to match $curr_head. - - eval_gettextln "Warning: fetch updated the current branch head. -Warning: fast-forwarding your working tree from -Warning: commit \$orig_head." >&2 - git update-index -q --refresh - git read-tree -u -m "$orig_head" "$curr_head" || - die "$(eval_gettext "Cannot fast-forward your working tree. -After making sure that you saved anything precious from -$ git diff \$orig_head -output, run -$ git reset --hard -to recover.")" - -fi - -merge_head=$(sed -e '/ not-for-merge /d' \ - -e 's/ .*//' "$GIT_DIR"/FETCH_HEAD | \ - tr '\012' ' ') - -case "$merge_head" in -'') - error_on_no_merge_candidates "$@" - ;; -?*' '?*) - if test -z "$orig_head" - then - die "$(gettext "Cannot merge multiple branches into empty head")" - fi - if test true = "$rebase" - then - die "$(gettext "Cannot rebase onto multiple branches")" - fi - ;; -esac - -# Pulling into unborn branch: a shorthand for branching off -# FETCH_HEAD, for lazy typers. -if test -z "$orig_head" -then - # Two-way merge: we claim the index is based on an empty tree, - # and try to fast-forward to HEAD. This ensures we will not - # lose index/worktree changes that the user already made on - # the unborn branch. - empty_tree=4b825dc642cb6eb9a060e54bf8d69288fbee4904 - git read-tree -m -u $empty_tree $merge_head && - git update-ref -m "initial pull" HEAD $merge_head "$curr_head" - exit -fi - -if test true = "$rebase" -then - o=$(git show-branch --merge-base $curr_branch $merge_head $oldremoteref) - if test "$oldremoteref" = "$o" - then - unset oldremoteref - fi -fi - -case "$rebase" in -true) - eval="git-rebase $diffstat $strategy_args $merge_args $rebase_args $verbosity" - eval="$eval $gpg_sign_args" - eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}" - ;; -*) - eval="git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only" - eval="$eval $log_arg $strategy_args $merge_args $verbosity $progress" - eval="$eval $gpg_sign_args" - eval="$eval FETCH_HEAD" - ;; -esac -eval "exec $eval" diff --git a/contrib/examples/git-remote.perl b/contrib/examples/git-remote.perl deleted file mode 100755 index d42df7b418..0000000000 --- a/contrib/examples/git-remote.perl +++ /dev/null @@ -1,474 +0,0 @@ -#!/usr/bin/perl -w - -use strict; -use Git; -my $git = Git->repository(); - -sub add_remote_config { - my ($hash, $name, $what, $value) = @_; - if ($what eq 'url') { - # Having more than one is Ok -- it is used for push. - if (! exists $hash->{'URL'}) { - $hash->{$name}{'URL'} = $value; - } - } - elsif ($what eq 'fetch') { - $hash->{$name}{'FETCH'} ||= []; - push @{$hash->{$name}{'FETCH'}}, $value; - } - elsif ($what eq 'push') { - $hash->{$name}{'PUSH'} ||= []; - push @{$hash->{$name}{'PUSH'}}, $value; - } - if (!exists $hash->{$name}{'SOURCE'}) { - $hash->{$name}{'SOURCE'} = 'config'; - } -} - -sub add_remote_remotes { - my ($hash, $file, $name) = @_; - - if (exists $hash->{$name}) { - $hash->{$name}{'WARNING'} = 'ignored due to config'; - return; - } - - my $fh; - if (!open($fh, '<', $file)) { - print STDERR "Warning: cannot open $file\n"; - return; - } - my $it = { 'SOURCE' => 'remotes' }; - $hash->{$name} = $it; - while (<$fh>) { - chomp; - if (/^URL:\s*(.*)$/) { - # Having more than one is Ok -- it is used for push. - if (! exists $it->{'URL'}) { - $it->{'URL'} = $1; - } - } - elsif (/^Push:\s*(.*)$/) { - $it->{'PUSH'} ||= []; - push @{$it->{'PUSH'}}, $1; - } - elsif (/^Pull:\s*(.*)$/) { - $it->{'FETCH'} ||= []; - push @{$it->{'FETCH'}}, $1; - } - elsif (/^\#/) { - ; # ignore - } - else { - print STDERR "Warning: funny line in $file: $_\n"; - } - } - close($fh); -} - -sub list_remote { - my ($git) = @_; - my %seen = (); - my @remotes = eval { - $git->command(qw(config --get-regexp), '^remote\.'); - }; - for (@remotes) { - if (/^remote\.(\S+?)\.([^.\s]+)\s+(.*)$/) { - add_remote_config(\%seen, $1, $2, $3); - } - } - - my $dir = $git->repo_path() . "/remotes"; - if (opendir(my $dh, $dir)) { - local $_; - while ($_ = readdir($dh)) { - chomp; - next if (! -f "$dir/$_" || ! -r _); - add_remote_remotes(\%seen, "$dir/$_", $_); - } - } - - return \%seen; -} - -sub add_branch_config { - my ($hash, $name, $what, $value) = @_; - if ($what eq 'remote') { - if (exists $hash->{$name}{'REMOTE'}) { - print STDERR "Warning: more than one branch.$name.remote\n"; - } - $hash->{$name}{'REMOTE'} = $value; - } - elsif ($what eq 'merge') { - $hash->{$name}{'MERGE'} ||= []; - push @{$hash->{$name}{'MERGE'}}, $value; - } -} - -sub list_branch { - my ($git) = @_; - my %seen = (); - my @branches = eval { - $git->command(qw(config --get-regexp), '^branch\.'); - }; - for (@branches) { - if (/^branch\.([^.]*)\.(\S*)\s+(.*)$/) { - add_branch_config(\%seen, $1, $2, $3); - } - } - - return \%seen; -} - -my $remote = list_remote($git); -my $branch = list_branch($git); - -sub update_ls_remote { - my ($harder, $info) = @_; - - return if (($harder == 0) || - (($harder == 1) && exists $info->{'LS_REMOTE'})); - - my @ref = map { s|refs/heads/||; $_; } keys %{$git->remote_refs($info->{'URL'}, [ 'heads' ])}; - $info->{'LS_REMOTE'} = \@ref; -} - -sub list_wildcard_mapping { - my ($forced, $ours, $ls) = @_; - my %refs; - for (@$ls) { - $refs{$_} = 01; # bit #0 to say "they have" - } - for ($git->command('for-each-ref', "refs/remotes/$ours")) { - chomp; - next unless (s|^[0-9a-f]{40}\s[a-z]+\srefs/remotes/$ours/||); - next if ($_ eq 'HEAD'); - $refs{$_} ||= 0; - $refs{$_} |= 02; # bit #1 to say "we have" - } - my (@new, @stale, @tracked); - for (sort keys %refs) { - my $have = $refs{$_}; - if ($have == 1) { - push @new, $_; - } - elsif ($have == 2) { - push @stale, $_; - } - elsif ($have == 3) { - push @tracked, $_; - } - } - return \@new, \@stale, \@tracked; -} - -sub list_mapping { - my ($name, $info) = @_; - my $fetch = $info->{'FETCH'}; - my $ls = $info->{'LS_REMOTE'}; - my (@new, @stale, @tracked); - - for (@$fetch) { - next unless (/(\+)?([^:]+):(.*)/); - my ($forced, $theirs, $ours) = ($1, $2, $3); - if ($theirs eq 'refs/heads/*' && - $ours =~ /^refs\/remotes\/(.*)\/\*$/) { - # wildcard mapping - my ($w_new, $w_stale, $w_tracked) - = list_wildcard_mapping($forced, $1, $ls); - push @new, @$w_new; - push @stale, @$w_stale; - push @tracked, @$w_tracked; - } - elsif ($theirs =~ /\*/ || $ours =~ /\*/) { - print STDERR "Warning: unrecognized mapping in remotes.$name.fetch: $_\n"; - } - elsif ($theirs =~ s|^refs/heads/||) { - if (!grep { $_ eq $theirs } @$ls) { - push @stale, $theirs; - } - elsif ($ours ne '') { - push @tracked, $theirs; - } - } - } - return \@new, \@stale, \@tracked; -} - -sub show_mapping { - my ($name, $info) = @_; - my ($new, $stale, $tracked) = list_mapping($name, $info); - if (@$new) { - print " New remote branches (next fetch will store in remotes/$name)\n"; - print " @$new\n"; - } - if (@$stale) { - print " Stale tracking branches in remotes/$name (use 'git remote prune')\n"; - print " @$stale\n"; - } - if (@$tracked) { - print " Tracked remote branches\n"; - print " @$tracked\n"; - } -} - -sub prune_remote { - my ($name, $ls_remote) = @_; - if (!exists $remote->{$name}) { - print STDERR "No such remote $name\n"; - return 1; - } - my $info = $remote->{$name}; - update_ls_remote($ls_remote, $info); - - my ($new, $stale, $tracked) = list_mapping($name, $info); - my $prefix = "refs/remotes/$name"; - foreach my $to_prune (@$stale) { - my @v = $git->command(qw(rev-parse --verify), "$prefix/$to_prune"); - $git->command(qw(update-ref -d), "$prefix/$to_prune", $v[0]); - } - return 0; -} - -sub show_remote { - my ($name, $ls_remote) = @_; - if (!exists $remote->{$name}) { - print STDERR "No such remote $name\n"; - return 1; - } - my $info = $remote->{$name}; - update_ls_remote($ls_remote, $info); - - print "* remote $name\n"; - print " URL: $info->{'URL'}\n"; - for my $branchname (sort keys %$branch) { - next unless (defined $branch->{$branchname}{'REMOTE'} && - $branch->{$branchname}{'REMOTE'} eq $name); - my @merged = map { - s|^refs/heads/||; - $_; - } split(' ',"@{$branch->{$branchname}{'MERGE'}}"); - next unless (@merged); - print " Remote branch(es) merged with 'git pull' while on branch $branchname\n"; - print " @merged\n"; - } - if ($info->{'LS_REMOTE'}) { - show_mapping($name, $info); - } - if ($info->{'PUSH'}) { - my @pushed = map { - s|^refs/heads/||; - s|^\+refs/heads/|+|; - s|:refs/heads/|:|; - $_; - } @{$info->{'PUSH'}}; - print " Local branch(es) pushed with 'git push'\n"; - print " @pushed\n"; - } - return 0; -} - -sub add_remote { - my ($name, $url, $opts) = @_; - if (exists $remote->{$name}) { - print STDERR "remote $name already exists.\n"; - exit(1); - } - $git->command('config', "remote.$name.url", $url); - my $track = $opts->{'track'} || ["*"]; - - for (@$track) { - $git->command('config', '--add', "remote.$name.fetch", - $opts->{'mirror'} ? - "+refs/$_:refs/$_" : - "+refs/heads/$_:refs/remotes/$name/$_"); - } - if ($opts->{'fetch'}) { - $git->command('fetch', $name); - } - if (exists $opts->{'master'}) { - $git->command('symbolic-ref', "refs/remotes/$name/HEAD", - "refs/remotes/$name/$opts->{'master'}"); - } -} - -sub update_remote { - my ($name) = @_; - my @remotes; - - my $conf = $git->config("remotes." . $name); - if (defined($conf)) { - @remotes = split(' ', $conf); - } elsif ($name eq 'default') { - @remotes = (); - for (sort keys %$remote) { - my $do_fetch = $git->config_bool("remote." . $_ . - ".skipDefaultUpdate"); - unless ($do_fetch) { - push @remotes, $_; - } - } - } else { - print STDERR "Remote group $name does not exist.\n"; - exit(1); - } - for (@remotes) { - print "Updating $_\n"; - $git->command('fetch', "$_"); - } -} - -sub rm_remote { - my ($name) = @_; - if (!exists $remote->{$name}) { - print STDERR "No such remote $name\n"; - return 1; - } - - $git->command('config', '--remove-section', "remote.$name"); - - eval { - my @trackers = $git->command('config', '--get-regexp', - 'branch.*.remote', $name); - for (@trackers) { - /^branch\.(.*)?\.remote/; - $git->config('--unset', "branch.$1.remote"); - $git->config('--unset', "branch.$1.merge"); - } - }; - - my @refs = $git->command('for-each-ref', - '--format=%(refname) %(objectname)', "refs/remotes/$name"); - for (@refs) { - my ($ref, $object) = split; - $git->command(qw(update-ref -d), $ref, $object); - } - return 0; -} - -sub add_usage { - print STDERR "usage: git remote add [-f] [-t track]* [-m master] <name> <url>\n"; - exit(1); -} - -my $VERBOSE = 0; -@ARGV = grep { - if ($_ eq '-v' or $_ eq '--verbose') { - $VERBOSE=1; - 0 - } else { - 1 - } -} @ARGV; - -if (!@ARGV) { - for (sort keys %$remote) { - print "$_"; - print "\t$remote->{$_}->{URL}" if $VERBOSE; - print "\n"; - } -} -elsif ($ARGV[0] eq 'show') { - my $ls_remote = 1; - my $i; - for ($i = 1; $i < @ARGV; $i++) { - if ($ARGV[$i] eq '-n') { - $ls_remote = 0; - } - else { - last; - } - } - if ($i >= @ARGV) { - print STDERR "usage: git remote show <remote>\n"; - exit(1); - } - my $status = 0; - for (; $i < @ARGV; $i++) { - $status |= show_remote($ARGV[$i], $ls_remote); - } - exit($status); -} -elsif ($ARGV[0] eq 'update') { - if (@ARGV <= 1) { - update_remote("default"); - exit(1); - } - for (my $i = 1; $i < @ARGV; $i++) { - update_remote($ARGV[$i]); - } -} -elsif ($ARGV[0] eq 'prune') { - my $ls_remote = 1; - my $i; - for ($i = 1; $i < @ARGV; $i++) { - if ($ARGV[$i] eq '-n') { - $ls_remote = 0; - } - else { - last; - } - } - if ($i >= @ARGV) { - print STDERR "usage: git remote prune <remote>\n"; - exit(1); - } - my $status = 0; - for (; $i < @ARGV; $i++) { - $status |= prune_remote($ARGV[$i], $ls_remote); - } - exit($status); -} -elsif ($ARGV[0] eq 'add') { - my %opts = (); - while (1 < @ARGV && $ARGV[1] =~ /^-/) { - my $opt = $ARGV[1]; - shift @ARGV; - if ($opt eq '-f' || $opt eq '--fetch') { - $opts{'fetch'} = 1; - next; - } - if ($opt eq '-t' || $opt eq '--track') { - if (@ARGV < 1) { - add_usage(); - } - $opts{'track'} ||= []; - push @{$opts{'track'}}, $ARGV[1]; - shift @ARGV; - next; - } - if ($opt eq '-m' || $opt eq '--master') { - if ((@ARGV < 1) || exists $opts{'master'}) { - add_usage(); - } - $opts{'master'} = $ARGV[1]; - shift @ARGV; - next; - } - if ($opt eq '--mirror') { - $opts{'mirror'} = 1; - next; - } - add_usage(); - } - if (@ARGV != 3) { - add_usage(); - } - add_remote($ARGV[1], $ARGV[2], \%opts); -} -elsif ($ARGV[0] eq 'rm') { - if (@ARGV <= 1) { - print STDERR "usage: git remote rm <remote>\n"; - exit(1); - } - exit(rm_remote($ARGV[1])); -} -else { - print STDERR "usage: git remote\n"; - print STDERR " git remote add <name> <url>\n"; - print STDERR " git remote rm <name>\n"; - print STDERR " git remote show <name>\n"; - print STDERR " git remote prune <name>\n"; - print STDERR " git remote update [group]\n"; - exit(1); -} diff --git a/contrib/examples/git-repack.sh b/contrib/examples/git-repack.sh deleted file mode 100755 index 672af93443..0000000000 --- a/contrib/examples/git-repack.sh +++ /dev/null @@ -1,194 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005 Linus Torvalds -# - -OPTIONS_KEEPDASHDASH= -OPTIONS_SPEC="\ -git repack [options] --- -a pack everything in a single pack -A same as -a, and turn unreachable objects loose -d remove redundant packs, and run git-prune-packed -f pass --no-reuse-delta to git-pack-objects -F pass --no-reuse-object to git-pack-objects -n do not run git-update-server-info -q,quiet be quiet -l pass --local to git-pack-objects -unpack-unreachable= with -A, do not loosen objects older than this - Packing constraints -window= size of the window used for delta compression -window-memory= same as the above, but limit memory size instead of entries count -depth= limits the maximum delta depth -max-pack-size= maximum size of each packfile -" -SUBDIRECTORY_OK='Yes' -. git-sh-setup - -no_update_info= all_into_one= remove_redundant= unpack_unreachable= -local= no_reuse= extra= -while test $# != 0 -do - case "$1" in - -n) no_update_info=t ;; - -a) all_into_one=t ;; - -A) all_into_one=t - unpack_unreachable=--unpack-unreachable ;; - --unpack-unreachable) - unpack_unreachable="--unpack-unreachable=$2"; shift ;; - -d) remove_redundant=t ;; - -q) GIT_QUIET=t ;; - -f) no_reuse=--no-reuse-delta ;; - -F) no_reuse=--no-reuse-object ;; - -l) local=--local ;; - --max-pack-size|--window|--window-memory|--depth) - extra="$extra $1=$2"; shift ;; - --) shift; break;; - *) usage ;; - esac - shift -done - -case "$(git config --bool repack.usedeltabaseoffset || echo true)" in -true) - extra="$extra --delta-base-offset" ;; -esac - -PACKDIR="$GIT_OBJECT_DIRECTORY/pack" -PACKTMP="$PACKDIR/.tmp-$$-pack" -rm -f "$PACKTMP"-* -trap 'rm -f "$PACKTMP"-*' 0 1 2 3 15 - -# There will be more repacking strategies to come... -case ",$all_into_one," in -,,) - args='--unpacked --incremental' - ;; -,t,) - args= existing= - if [ -d "$PACKDIR" ]; then - for e in $(cd "$PACKDIR" && find . -type f -name '*.pack' \ - | sed -e 's/^\.\///' -e 's/\.pack$//') - do - if [ -e "$PACKDIR/$e.keep" ]; then - : keep - else - existing="$existing $e" - fi - done - if test -n "$existing" && test -n "$unpack_unreachable" && \ - test -n "$remove_redundant" - then - # This may have arbitrary user arguments, so we - # have to protect it against whitespace splitting - # when it gets run as "pack-objects $args" later. - # Fortunately, we know it's an approxidate, so we - # can just use dots instead. - args="$args $(echo "$unpack_unreachable" | tr ' ' .)" - fi - fi - ;; -esac - -mkdir -p "$PACKDIR" || exit - -args="$args $local ${GIT_QUIET:+-q} $no_reuse$extra" -names=$(git pack-objects --keep-true-parents --honor-pack-keep --non-empty --all --reflog $args </dev/null "$PACKTMP") || - exit 1 -if [ -z "$names" ]; then - say Nothing new to pack. -fi - -# Ok we have prepared all new packfiles. - -# First see if there are packs of the same name and if so -# if we can move them out of the way (this can happen if we -# repacked immediately after packing fully. -rollback= -failed= -for name in $names -do - for sfx in pack idx - do - file=pack-$name.$sfx - test -f "$PACKDIR/$file" || continue - rm -f "$PACKDIR/old-$file" && - mv "$PACKDIR/$file" "$PACKDIR/old-$file" || { - failed=t - break - } - rollback="$rollback $file" - done - test -z "$failed" || break -done - -# If renaming failed for any of them, roll the ones we have -# already renamed back to their original names. -if test -n "$failed" -then - rollback_failure= - for file in $rollback - do - mv "$PACKDIR/old-$file" "$PACKDIR/$file" || - rollback_failure="$rollback_failure $file" - done - if test -n "$rollback_failure" - then - echo >&2 "WARNING: Some packs in use have been renamed by" - echo >&2 "WARNING: prefixing old- to their name, in order to" - echo >&2 "WARNING: replace them with the new version of the" - echo >&2 "WARNING: file. But the operation failed, and" - echo >&2 "WARNING: attempt to rename them back to their" - echo >&2 "WARNING: original names also failed." - echo >&2 "WARNING: Please rename them in $PACKDIR manually:" - for file in $rollback_failure - do - echo >&2 "WARNING: old-$file -> $file" - done - fi - exit 1 -fi - -# Now the ones with the same name are out of the way... -fullbases= -for name in $names -do - fullbases="$fullbases pack-$name" - chmod a-w "$PACKTMP-$name.pack" - chmod a-w "$PACKTMP-$name.idx" - mv -f "$PACKTMP-$name.pack" "$PACKDIR/pack-$name.pack" && - mv -f "$PACKTMP-$name.idx" "$PACKDIR/pack-$name.idx" || - exit -done - -# Remove the "old-" files -for name in $names -do - rm -f "$PACKDIR/old-pack-$name.idx" - rm -f "$PACKDIR/old-pack-$name.pack" -done - -# End of pack replacement. - -if test "$remove_redundant" = t -then - # We know $existing are all redundant. - if [ -n "$existing" ] - then - ( cd "$PACKDIR" && - for e in $existing - do - case " $fullbases " in - *" $e "*) ;; - *) rm -f "$e.pack" "$e.idx" "$e.keep" ;; - esac - done - ) - fi - git prune-packed ${GIT_QUIET:+-q} -fi - -case "$no_update_info" in -t) : ;; -*) git update-server-info ;; -esac diff --git a/contrib/examples/git-rerere.perl b/contrib/examples/git-rerere.perl deleted file mode 100755 index 4f692091e7..0000000000 --- a/contrib/examples/git-rerere.perl +++ /dev/null @@ -1,284 +0,0 @@ -#!/usr/bin/perl -# -# REuse REcorded REsolve. This tool records a conflicted automerge -# result and its hand resolution, and helps to resolve future -# automerge that results in the same conflict. -# -# To enable this feature, create a directory 'rr-cache' under your -# .git/ directory. - -use Digest; -use File::Path; -use File::Copy; - -my $git_dir = $::ENV{GIT_DIR} || ".git"; -my $rr_dir = "$git_dir/rr-cache"; -my $merge_rr = "$git_dir/rr-cache/MERGE_RR"; - -my %merge_rr = (); - -sub read_rr { - if (!-f $merge_rr) { - %merge_rr = (); - return; - } - my $in; - local $/ = "\0"; - open $in, "<$merge_rr" or die "$!: $merge_rr"; - while (<$in>) { - chomp; - my ($name, $path) = /^([0-9a-f]{40})\t(.*)$/s; - $merge_rr{$path} = $name; - } - close $in; -} - -sub write_rr { - my $out; - open $out, ">$merge_rr" or die "$!: $merge_rr"; - for my $path (sort keys %merge_rr) { - my $name = $merge_rr{$path}; - print $out "$name\t$path\0"; - } - close $out; -} - -sub compute_conflict_name { - my ($path) = @_; - my @side = (); - my $in; - open $in, "<$path" or die "$!: $path"; - - my $sha1 = Digest->new("SHA-1"); - my $hunk = 0; - while (<$in>) { - if (/^<<<<<<< .*/) { - $hunk++; - @side = ([], undef); - } - elsif (/^=======$/) { - $side[1] = []; - } - elsif (/^>>>>>>> .*/) { - my ($one, $two); - $one = join('', @{$side[0]}); - $two = join('', @{$side[1]}); - if ($two le $one) { - ($one, $two) = ($two, $one); - } - $sha1->add($one); - $sha1->add("\0"); - $sha1->add($two); - $sha1->add("\0"); - @side = (); - } - elsif (@side == 0) { - next; - } - elsif (defined $side[1]) { - push @{$side[1]}, $_; - } - else { - push @{$side[0]}, $_; - } - } - close $in; - return ($sha1->hexdigest, $hunk); -} - -sub record_preimage { - my ($path, $name) = @_; - my @side = (); - my ($in, $out); - open $in, "<$path" or die "$!: $path"; - open $out, ">$name" or die "$!: $name"; - - while (<$in>) { - if (/^<<<<<<< .*/) { - @side = ([], undef); - } - elsif (/^=======$/) { - $side[1] = []; - } - elsif (/^>>>>>>> .*/) { - my ($one, $two); - $one = join('', @{$side[0]}); - $two = join('', @{$side[1]}); - if ($two le $one) { - ($one, $two) = ($two, $one); - } - print $out "<<<<<<<\n"; - print $out $one; - print $out "=======\n"; - print $out $two; - print $out ">>>>>>>\n"; - @side = (); - } - elsif (@side == 0) { - print $out $_; - } - elsif (defined $side[1]) { - push @{$side[1]}, $_; - } - else { - push @{$side[0]}, $_; - } - } - close $out; - close $in; -} - -sub find_conflict { - my $in; - local $/ = "\0"; - my $pid = open($in, '-|'); - die "$!" unless defined $pid; - if (!$pid) { - exec(qw(git ls-files -z -u)) or die "$!: ls-files"; - } - my %path = (); - my @path = (); - while (<$in>) { - chomp; - my ($mode, $sha1, $stage, $path) = - /^([0-7]+) ([0-9a-f]{40}) ([123])\t(.*)$/s; - $path{$path} |= (1 << $stage); - } - close $in; - while (my ($path, $status) = each %path) { - if ($status == 14) { push @path, $path; } - } - return @path; -} - -sub merge { - my ($name, $path) = @_; - record_preimage($path, "$rr_dir/$name/thisimage"); - unless (system('git', 'merge-file', map { "$rr_dir/$name/${_}image" } - qw(this pre post))) { - my $in; - open $in, "<$rr_dir/$name/thisimage" or - die "$!: $name/thisimage"; - my $out; - open $out, ">$path" or die "$!: $path"; - while (<$in>) { print $out $_; } - close $in; - close $out; - return 1; - } - return 0; -} - -sub garbage_collect_rerere { - # We should allow specifying these from the command line and - # that is why the caller gives @ARGV to us, but I am lazy. - - my $cutoff_noresolve = 15; # two weeks - my $cutoff_resolve = 60; # two months - my @to_remove; - while (<$rr_dir/*/preimage>) { - my ($dir) = /^(.*)\/preimage$/; - my $cutoff = ((-f "$dir/postimage") - ? $cutoff_resolve - : $cutoff_noresolve); - my $age = -M "$_"; - if ($cutoff <= $age) { - push @to_remove, $dir; - } - } - if (@to_remove) { - rmtree(\@to_remove); - } -} - --d "$rr_dir" || exit(0); - -read_rr(); - -if (@ARGV) { - my $arg = shift @ARGV; - if ($arg eq 'clear') { - for my $path (keys %merge_rr) { - my $name = $merge_rr{$path}; - if (-d "$rr_dir/$name" && - ! -f "$rr_dir/$name/postimage") { - rmtree(["$rr_dir/$name"]); - } - } - unlink $merge_rr; - } - elsif ($arg eq 'status') { - for my $path (keys %merge_rr) { - print $path, "\n"; - } - } - elsif ($arg eq 'diff') { - for my $path (keys %merge_rr) { - my $name = $merge_rr{$path}; - system('diff', ((@ARGV == 0) ? ('-u') : @ARGV), - '-L', "a/$path", '-L', "b/$path", - "$rr_dir/$name/preimage", $path); - } - } - elsif ($arg eq 'gc') { - garbage_collect_rerere(@ARGV); - } - else { - die "$0 unknown command: $arg\n"; - } - exit 0; -} - -my %conflict = map { $_ => 1 } find_conflict(); - -# MERGE_RR records paths with conflicts immediately after merge -# failed. Some of the conflicted paths might have been hand resolved -# in the working tree since then, but the initial run would catch all -# and register their preimages. - -for my $path (keys %conflict) { - # This path has conflict. If it is not recorded yet, - # record the pre-image. - if (!exists $merge_rr{$path}) { - my ($name, $hunk) = compute_conflict_name($path); - next unless ($hunk); - $merge_rr{$path} = $name; - if (! -d "$rr_dir/$name") { - mkpath("$rr_dir/$name", 0, 0777); - print STDERR "Recorded preimage for '$path'\n"; - record_preimage($path, "$rr_dir/$name/preimage"); - } - } -} - -# Now some of the paths that had conflicts earlier might have been -# hand resolved. Others may be similar to a conflict already that -# was resolved before. - -for my $path (keys %merge_rr) { - my $name = $merge_rr{$path}; - - # We could resolve this automatically if we have images. - if (-f "$rr_dir/$name/preimage" && - -f "$rr_dir/$name/postimage") { - if (merge($name, $path)) { - print STDERR "Resolved '$path' using previous resolution.\n"; - # Then we do not have to worry about this path - # anymore. - delete $merge_rr{$path}; - next; - } - } - - # Let's see if we have resolved it. - (undef, my $hunk) = compute_conflict_name($path); - next if ($hunk); - - print STDERR "Recorded resolution for '$path'.\n"; - copy($path, "$rr_dir/$name/postimage"); - # And we do not have to worry about this path anymore. - delete $merge_rr{$path}; -} - -# Write out the rest. -write_rr(); diff --git a/contrib/examples/git-reset.sh b/contrib/examples/git-reset.sh deleted file mode 100755 index cb1bbf3b90..0000000000 --- a/contrib/examples/git-reset.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano -# -USAGE='[--mixed | --soft | --hard] [<commit-ish>] [ [--] <paths>...]' -SUBDIRECTORY_OK=Yes -. git-sh-setup -set_reflog_action "reset $*" -require_work_tree - -update= reset_type=--mixed -unset rev - -while test $# != 0 -do - case "$1" in - --mixed | --soft | --hard) - reset_type="$1" - ;; - --) - break - ;; - -*) - usage - ;; - *) - rev=$(git rev-parse --verify "$1") || exit - shift - break - ;; - esac - shift -done - -: ${rev=HEAD} -rev=$(git rev-parse --verify $rev^0) || exit - -# Skip -- in "git reset HEAD -- foo" and "git reset -- foo". -case "$1" in --) shift ;; esac - -# git reset --mixed tree [--] paths... can be used to -# load chosen paths from the tree into the index without -# affecting the working tree or HEAD. -if test $# != 0 -then - test "$reset_type" = "--mixed" || - die "Cannot do partial $reset_type reset." - - git diff-index --cached $rev -- "$@" | - sed -e 's/^:\([0-7][0-7]*\) [0-7][0-7]* \([0-9a-f][0-9a-f]*\) [0-9a-f][0-9a-f]* [A-Z] \(.*\)$/\1 \2 \3/' | - git update-index --add --remove --index-info || exit - git update-index --refresh - exit -fi - -cd_to_toplevel - -if test "$reset_type" = "--hard" -then - update=-u -fi - -# Soft reset does not touch the index file or the working tree -# at all, but requires them in a good order. Other resets reset -# the index file to the tree object we are switching to. -if test "$reset_type" = "--soft" -then - if test -f "$GIT_DIR/MERGE_HEAD" || - test "" != "$(git ls-files --unmerged)" - then - die "Cannot do a soft reset in the middle of a merge." - fi -else - git read-tree -v --reset $update "$rev" || exit -fi - -# Any resets update HEAD to the head being switched to. -if orig=$(git rev-parse --verify HEAD 2>/dev/null) -then - echo "$orig" >"$GIT_DIR/ORIG_HEAD" -else - rm -f "$GIT_DIR/ORIG_HEAD" -fi -git update-ref -m "$GIT_REFLOG_ACTION" HEAD "$rev" -update_ref_status=$? - -case "$reset_type" in ---hard ) - test $update_ref_status = 0 && { - printf "HEAD is now at " - GIT_PAGER= git log --max-count=1 --pretty=oneline \ - --abbrev-commit HEAD - } - ;; ---soft ) - ;; # Nothing else to do ---mixed ) - # Report what has not been updated. - git update-index --refresh - ;; -esac - -rm -f "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/rr-cache/MERGE_RR" \ - "$GIT_DIR/SQUASH_MSG" "$GIT_DIR/MERGE_MSG" - -exit $update_ref_status diff --git a/contrib/examples/git-resolve.sh b/contrib/examples/git-resolve.sh deleted file mode 100755 index 3099dc851a..0000000000 --- a/contrib/examples/git-resolve.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005 Linus Torvalds -# -# Resolve two trees. -# - -echo 'WARNING: This command is DEPRECATED and will be removed very soon.' >&2 -echo 'WARNING: Please use git-merge or git-pull instead.' >&2 -sleep 2 - -USAGE='<head> <remote> <merge-message>' -. git-sh-setup - -dropheads() { - rm -f -- "$GIT_DIR/MERGE_HEAD" \ - "$GIT_DIR/LAST_MERGE" || exit 1 -} - -head=$(git rev-parse --verify "$1"^0) && -merge=$(git rev-parse --verify "$2"^0) && -merge_name="$2" && -merge_msg="$3" || usage - -# -# The remote name is just used for the message, -# but we do want it. -# -if [ -z "$head" -o -z "$merge" -o -z "$merge_msg" ]; then - usage -fi - -dropheads -echo $head > "$GIT_DIR"/ORIG_HEAD -echo $merge > "$GIT_DIR"/LAST_MERGE - -common=$(git merge-base $head $merge) -if [ -z "$common" ]; then - die "Unable to find common commit between" $merge $head -fi - -case "$common" in -"$merge") - echo "Already up to date. Yeeah!" - dropheads - exit 0 - ;; -"$head") - echo "Updating $(git rev-parse --short $head)..$(git rev-parse --short $merge)" - git read-tree -u -m $head $merge || exit 1 - git update-ref -m "resolve $merge_name: Fast-forward" \ - HEAD "$merge" "$head" - git diff-tree -p $head $merge | git apply --stat - dropheads - exit 0 - ;; -esac - -# We are going to make a new commit. -git var GIT_COMMITTER_IDENT >/dev/null || exit - -# Find an optimum merge base if there are more than one candidates. -LF=' -' -common=$(git merge-base -a $head $merge) -case "$common" in -?*"$LF"?*) - echo "Trying to find the optimum merge base." - G=.tmp-index$$ - best= - best_cnt=-1 - for c in $common - do - rm -f $G - GIT_INDEX_FILE=$G git read-tree -m $c $head $merge \ - 2>/dev/null || continue - # Count the paths that are unmerged. - cnt=$(GIT_INDEX_FILE=$G git ls-files --unmerged | wc -l) - if test $best_cnt -le 0 || test $cnt -le $best_cnt - then - best=$c - best_cnt=$cnt - if test "$best_cnt" -eq 0 - then - # Cannot do any better than all trivial merge. - break - fi - fi - done - rm -f $G - common="$best" -esac - -echo "Trying to merge $merge into $head using $common." -git update-index --refresh 2>/dev/null -git read-tree -u -m $common $head $merge || exit 1 -result_tree=$(git write-tree 2> /dev/null) -if [ $? -ne 0 ]; then - echo "Simple merge failed, trying Automatic merge" - git-merge-index -o git-merge-one-file -a - if [ $? -ne 0 ]; then - echo $merge > "$GIT_DIR"/MERGE_HEAD - die "Automatic merge failed, fix up by hand" - fi - result_tree=$(git write-tree) || exit 1 -fi -result_commit=$(echo "$merge_msg" | git commit-tree $result_tree -p $head -p $merge) -echo "Committed merge $result_commit" -git update-ref -m "resolve $merge_name: In-index merge" \ - HEAD "$result_commit" "$head" -git diff-tree -p $head $result_commit | git apply --stat -dropheads diff --git a/contrib/examples/git-revert.sh b/contrib/examples/git-revert.sh deleted file mode 100755 index 197838d10b..0000000000 --- a/contrib/examples/git-revert.sh +++ /dev/null @@ -1,207 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005 Linus Torvalds -# Copyright (c) 2005 Junio C Hamano -# - -case "$0" in -*-revert* ) - test -t 0 && edit=-e - replay= - me=revert - USAGE='[--edit | --no-edit] [-n] <commit-ish>' ;; -*-cherry-pick* ) - replay=t - edit= - me=cherry-pick - USAGE='[--edit] [-n] [-r] [-x] <commit-ish>' ;; -* ) - echo >&2 "What are you talking about?" - exit 1 ;; -esac - -SUBDIRECTORY_OK=Yes ;# we will cd up -. git-sh-setup -require_work_tree -cd_to_toplevel - -no_commit= -xopt= -while case "$#" in 0) break ;; esac -do - case "$1" in - -n|--n|--no|--no-|--no-c|--no-co|--no-com|--no-comm|\ - --no-commi|--no-commit) - no_commit=t - ;; - -e|--e|--ed|--edi|--edit) - edit=-e - ;; - --n|--no|--no-|--no-e|--no-ed|--no-edi|--no-edit) - edit= - ;; - -r) - : no-op ;; - -x|--i-really-want-to-expose-my-private-commit-object-name) - replay= - ;; - -X?*) - xopt="$xopt$(git rev-parse --sq-quote "--${1#-X}")" - ;; - --strategy-option=*) - xopt="$xopt$(git rev-parse --sq-quote "--${1#--strategy-option=}")" - ;; - -X|--strategy-option) - shift - xopt="$xopt$(git rev-parse --sq-quote "--$1")" - ;; - -*) - usage - ;; - *) - break - ;; - esac - shift -done - -set_reflog_action "$me" - -test "$me,$replay" = "revert,t" && usage - -case "$no_commit" in -t) - # We do not intend to commit immediately. We just want to - # merge the differences in. - head=$(git-write-tree) || - die "Your index file is unmerged." - ;; -*) - head=$(git-rev-parse --verify HEAD) || - die "You do not have a valid HEAD" - files=$(git-diff-index --cached --name-only $head) || exit - if [ "$files" ]; then - die "Dirty index: cannot $me (dirty: $files)" - fi - ;; -esac - -rev=$(git-rev-parse --verify "$@") && -commit=$(git-rev-parse --verify "$rev^0") || - die "Not a single commit $@" -prev=$(git-rev-parse --verify "$commit^1" 2>/dev/null) || - die "Cannot run $me a root commit" -git-rev-parse --verify "$commit^2" >/dev/null 2>&1 && - die "Cannot run $me a multi-parent commit." - -encoding=$(git config i18n.commitencoding || echo UTF-8) - -# "commit" is an existing commit. We would want to apply -# the difference it introduces since its first parent "prev" -# on top of the current HEAD if we are cherry-pick. Or the -# reverse of it if we are revert. - -case "$me" in -revert) - git show -s --pretty=oneline --encoding="$encoding" $commit | - sed -e ' - s/^[^ ]* /Revert "/ - s/$/"/ - ' - echo - echo "This reverts commit $commit." - test "$rev" = "$commit" || - echo "(original 'git revert' arguments: $@)" - base=$commit next=$prev - ;; - -cherry-pick) - pick_author_script=' - /^author /{ - s/'\''/'\''\\'\'\''/g - h - s/^author \([^<]*\) <[^>]*> .*$/\1/ - s/'\''/'\''\'\'\''/g - s/.*/GIT_AUTHOR_NAME='\''&'\''/p - - g - s/^author [^<]* <\([^>]*\)> .*$/\1/ - s/'\''/'\''\'\'\''/g - s/.*/GIT_AUTHOR_EMAIL='\''&'\''/p - - g - s/^author [^<]* <[^>]*> \(.*\)$/\1/ - s/'\''/'\''\'\'\''/g - s/.*/GIT_AUTHOR_DATE='\''&'\''/p - - q - }' - - logmsg=$(git show -s --pretty=raw --encoding="$encoding" "$commit") - set_author_env=$(echo "$logmsg" | - LANG=C LC_ALL=C sed -ne "$pick_author_script") - eval "$set_author_env" - export GIT_AUTHOR_NAME - export GIT_AUTHOR_EMAIL - export GIT_AUTHOR_DATE - - echo "$logmsg" | - sed -e '1,/^$/d' -e 's/^ //' - case "$replay" in - '') - echo "(cherry picked from commit $commit)" - test "$rev" = "$commit" || - echo "(original 'git cherry-pick' arguments: $@)" - ;; - esac - base=$prev next=$commit - ;; - -esac >.msg - -eval GITHEAD_$head=HEAD -eval GITHEAD_$next='$(git show -s \ - --pretty=oneline --encoding="$encoding" "$commit" | - sed -e "s/^[^ ]* //")' -export GITHEAD_$head GITHEAD_$next - -# This three way merge is an interesting one. We are at -# $head, and would want to apply the change between $commit -# and $prev on top of us (when reverting), or the change between -# $prev and $commit on top of us (when cherry-picking or replaying). - -eval "git merge-recursive $xopt $base -- $head $next" && -result=$(git-write-tree 2>/dev/null) || { - mv -f .msg "$GIT_DIR/MERGE_MSG" - { - echo ' -Conflicts: -' - git ls-files --unmerged | - sed -e 's/^[^ ]* / /' | - uniq - } >>"$GIT_DIR/MERGE_MSG" - echo >&2 "Automatic $me failed. After resolving the conflicts," - echo >&2 "mark the corrected paths with 'git-add <paths>'" - echo >&2 "and commit the result." - case "$me" in - cherry-pick) - echo >&2 "You may choose to use the following when making" - echo >&2 "the commit:" - echo >&2 "$set_author_env" - esac - exit 1 -} - -# If we are cherry-pick, and if the merge did not result in -# hand-editing, we will hit this commit and inherit the original -# author date and name. -# If we are revert, or if our cherry-pick results in a hand merge, -# we had better say that the current user is responsible for that. - -case "$no_commit" in -'') - git-commit -n -F .msg $edit - rm -f .msg - ;; -esac diff --git a/contrib/examples/git-svnimport.perl b/contrib/examples/git-svnimport.perl deleted file mode 100755 index c414f0d9c7..0000000000 --- a/contrib/examples/git-svnimport.perl +++ /dev/null @@ -1,976 +0,0 @@ -#!/usr/bin/perl - -# This tool is copyright (c) 2005, Matthias Urlichs. -# It is released under the Gnu Public License, version 2. -# -# The basic idea is to pull and analyze SVN changes. -# -# Checking out the files is done by a single long-running SVN connection. -# -# The head revision is on branch "origin" by default. -# You can change that with the '-o' option. - -use strict; -use warnings; -use Getopt::Std; -use File::Copy; -use File::Spec; -use File::Temp qw(tempfile); -use File::Path qw(mkpath); -use File::Basename qw(basename dirname); -use Time::Local; -use IO::Pipe; -use POSIX qw(strftime dup2); -use IPC::Open2; -use SVN::Core; -use SVN::Ra; - -die "Need SVN:Core 1.2.1 or better" if $SVN::Core::VERSION lt "1.2.1"; - -$SIG{'PIPE'}="IGNORE"; -$ENV{'TZ'}="UTC"; - -our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T, - $opt_b,$opt_r,$opt_I,$opt_A,$opt_s,$opt_l,$opt_d,$opt_D,$opt_S,$opt_F, - $opt_P,$opt_R); - -sub usage() { - print STDERR <<END; -usage: ${\basename $0} # fetch/update GIT from SVN - [-o branch-for-HEAD] [-h] [-v] [-l max_rev] [-R repack_each_revs] - [-C GIT_repository] [-t tagname] [-T trunkname] [-b branchname] - [-d|-D] [-i] [-u] [-r] [-I ignorefilename] [-s start_chg] - [-m] [-M regex] [-A author_file] [-S] [-F] [-P project_name] [SVN_URL] -END - exit(1); -} - -getopts("A:b:C:dDFhiI:l:mM:o:rs:t:T:SP:R:uv") or usage(); -usage if $opt_h; - -my $tag_name = $opt_t || "tags"; -my $trunk_name = defined $opt_T ? $opt_T : "trunk"; -my $branch_name = $opt_b || "branches"; -my $project_name = $opt_P || ""; -$project_name = "/" . $project_name if ($project_name); -my $repack_after = $opt_R || 1000; -my $root_pool = SVN::Pool->new_default; - -@ARGV == 1 or @ARGV == 2 or usage(); - -$opt_o ||= "origin"; -$opt_s ||= 1; -my $git_tree = $opt_C; -$git_tree ||= "."; - -my $svn_url = $ARGV[0]; -my $svn_dir = $ARGV[1]; - -our @mergerx = (); -if ($opt_m) { - my $branch_esc = quotemeta ($branch_name); - my $trunk_esc = quotemeta ($trunk_name); - @mergerx = - ( - qr!\b(?:merg(?:ed?|ing))\b.*?\b((?:(?<=$branch_esc/)[\w\.\-]+)|(?:$trunk_esc))\b!i, - qr!\b(?:from|of)\W+((?:(?<=$branch_esc/)[\w\.\-]+)|(?:$trunk_esc))\b!i, - qr!\b(?:from|of)\W+(?:the )?([\w\.\-]+)[-\s]branch\b!i - ); -} -if ($opt_M) { - unshift (@mergerx, qr/$opt_M/); -} - -# Absolutize filename now, since we will have chdir'ed by the time we -# get around to opening it. -$opt_A = File::Spec->rel2abs($opt_A) if $opt_A; - -our %users = (); -our $users_file = undef; -sub read_users($) { - $users_file = File::Spec->rel2abs(@_); - die "Cannot open $users_file\n" unless -f $users_file; - open(my $authors,$users_file); - while(<$authors>) { - chomp; - next unless /^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*$/; - (my $user,my $name,my $email) = ($1,$2,$3); - $users{$user} = [$name,$email]; - } - close($authors); -} - -select(STDERR); $|=1; select(STDOUT); - - -package SVNconn; -# Basic SVN connection. -# We're only interested in connecting and downloading, so ... - -use File::Spec; -use File::Temp qw(tempfile); -use POSIX qw(strftime dup2); -use Fcntl qw(SEEK_SET); - -sub new { - my($what,$repo) = @_; - $what=ref($what) if ref($what); - - my $self = {}; - $self->{'buffer'} = ""; - bless($self,$what); - - $repo =~ s#/+$##; - $self->{'fullrep'} = $repo; - $self->conn(); - - return $self; -} - -sub conn { - my $self = shift; - my $repo = $self->{'fullrep'}; - my $auth = SVN::Core::auth_open ([SVN::Client::get_simple_provider, - SVN::Client::get_ssl_server_trust_file_provider, - SVN::Client::get_username_provider]); - my $s = SVN::Ra->new(url => $repo, auth => $auth, pool => $root_pool); - die "SVN connection to $repo: $!\n" unless defined $s; - $self->{'svn'} = $s; - $self->{'repo'} = $repo; - $self->{'maxrev'} = $s->get_latest_revnum(); -} - -sub file { - my($self,$path,$rev) = @_; - - my ($fh, $name) = tempfile('gitsvn.XXXXXX', - DIR => File::Spec->tmpdir(), UNLINK => 1); - - print "... $rev $path ...\n" if $opt_v; - my (undef, $properties); - $path =~ s#^/*##; - my $subpool = SVN::Pool::new_default_sub; - eval { (undef, $properties) - = $self->{'svn'}->get_file($path,$rev,$fh); }; - if($@) { - return undef if $@ =~ /Attempted to get checksum/; - die $@; - } - my $mode; - if (exists $properties->{'svn:executable'}) { - $mode = '100755'; - } elsif (exists $properties->{'svn:special'}) { - my ($special_content, $filesize); - $filesize = tell $fh; - seek $fh, 0, SEEK_SET; - read $fh, $special_content, $filesize; - if ($special_content =~ s/^link //) { - $mode = '120000'; - seek $fh, 0, SEEK_SET; - truncate $fh, 0; - print $fh $special_content; - } else { - die "unexpected svn:special file encountered"; - } - } else { - $mode = '100644'; - } - close ($fh); - - return ($name, $mode); -} - -sub ignore { - my($self,$path,$rev) = @_; - - print "... $rev $path ...\n" if $opt_v; - $path =~ s#^/*##; - my $subpool = SVN::Pool::new_default_sub; - my (undef,undef,$properties) - = $self->{'svn'}->get_dir($path,$rev,undef); - if (exists $properties->{'svn:ignore'}) { - my ($fh, $name) = tempfile('gitsvn.XXXXXX', - DIR => File::Spec->tmpdir(), - UNLINK => 1); - print $fh $properties->{'svn:ignore'}; - close($fh); - return $name; - } else { - return undef; - } -} - -sub dir_list { - my($self,$path,$rev) = @_; - $path =~ s#^/*##; - my $subpool = SVN::Pool::new_default_sub; - my ($dirents,undef,$properties) - = $self->{'svn'}->get_dir($path,$rev,undef); - return $dirents; -} - -package main; -use URI; - -our $svn = $svn_url; -$svn .= "/$svn_dir" if defined $svn_dir; -my $svn2 = SVNconn->new($svn); -$svn = SVNconn->new($svn); - -my $lwp_ua; -if($opt_d or $opt_D) { - $svn_url = URI->new($svn_url)->canonical; - if($opt_D) { - $svn_dir =~ s#/*$#/#; - } else { - $svn_dir = ""; - } - if ($svn_url->scheme eq "http") { - use LWP::UserAgent; - $lwp_ua = LWP::UserAgent->new(keep_alive => 1, requests_redirectable => []); - } else { - print STDERR "Warning: not HTTP; turning off direct file access\n"; - $opt_d=0; - } -} - -sub pdate($) { - my($d) = @_; - $d =~ m#(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)# - or die "Unparseable date: $d\n"; - my $y=$1; $y-=1900 if $y>1900; - return timegm($6||0,$5,$4,$3,$2-1,$y); -} - -sub getwd() { - my $pwd = `pwd`; - chomp $pwd; - return $pwd; -} - - -sub get_headref($$) { - my $name = shift; - my $git_dir = shift; - my $sha; - - if (open(C,"$git_dir/refs/heads/$name")) { - chomp($sha = <C>); - close(C); - length($sha) == 40 - or die "Cannot get head id for $name ($sha): $!\n"; - } - return $sha; -} - - --d $git_tree - or mkdir($git_tree,0777) - or die "Could not create $git_tree: $!"; -chdir($git_tree); - -my $orig_branch = ""; -my $forward_master = 0; -my %branches; - -my $git_dir = $ENV{"GIT_DIR"} || ".git"; -$git_dir = getwd()."/".$git_dir unless $git_dir =~ m#^/#; -$ENV{"GIT_DIR"} = $git_dir; -my $orig_git_index; -$orig_git_index = $ENV{GIT_INDEX_FILE} if exists $ENV{GIT_INDEX_FILE}; -my ($git_ih, $git_index) = tempfile('gitXXXXXX', SUFFIX => '.idx', - DIR => File::Spec->tmpdir()); -close ($git_ih); -$ENV{GIT_INDEX_FILE} = $git_index; -my $maxnum = 0; -my $last_rev = ""; -my $last_branch; -my $current_rev = $opt_s || 1; -unless(-d $git_dir) { - system("git init"); - die "Cannot init the GIT db at $git_tree: $?\n" if $?; - system("git read-tree --empty"); - die "Cannot init an empty tree: $?\n" if $?; - - $last_branch = $opt_o; - $orig_branch = ""; -} else { - -f "$git_dir/refs/heads/$opt_o" - or die "Branch '$opt_o' does not exist.\n". - "Either use the correct '-o branch' option,\n". - "or import to a new repository.\n"; - - -f "$git_dir/svn2git" - or die "'$git_dir/svn2git' does not exist.\n". - "You need that file for incremental imports.\n"; - open(F, "git symbolic-ref HEAD |") or - die "Cannot run git-symbolic-ref: $!\n"; - chomp ($last_branch = <F>); - $last_branch = basename($last_branch); - close(F); - unless($last_branch) { - warn "Cannot read the last branch name: $! -- assuming 'master'\n"; - $last_branch = "master"; - } - $orig_branch = $last_branch; - $last_rev = get_headref($orig_branch, $git_dir); - if (-f "$git_dir/SVN2GIT_HEAD") { - die <<EOM; -SVN2GIT_HEAD exists. -Make sure your working directory corresponds to HEAD and remove SVN2GIT_HEAD. -You may need to run - - git-read-tree -m -u SVN2GIT_HEAD HEAD -EOM - } - system('cp', "$git_dir/HEAD", "$git_dir/SVN2GIT_HEAD"); - - $forward_master = - $opt_o ne 'master' && -f "$git_dir/refs/heads/master" && - system('cmp', '-s', "$git_dir/refs/heads/master", - "$git_dir/refs/heads/$opt_o") == 0; - - # populate index - system('git', 'read-tree', $last_rev); - die "read-tree failed: $?\n" if $?; - - # Get the last import timestamps - open my $B,"<", "$git_dir/svn2git"; - while(<$B>) { - chomp; - my($num,$branch,$ref) = split; - $branches{$branch}{$num} = $ref; - $branches{$branch}{"LAST"} = $ref; - $current_rev = $num+1 if $current_rev <= $num; - } - close($B); -} --d $git_dir - or die "Could not create git subdir ($git_dir).\n"; - -my $default_authors = "$git_dir/svn-authors"; -if ($opt_A) { - read_users($opt_A); - copy($opt_A,$default_authors) or die "Copy failed: $!"; -} else { - read_users($default_authors) if -f $default_authors; -} - -open BRANCHES,">>", "$git_dir/svn2git"; - -sub node_kind($$) { - my ($svnpath, $revision) = @_; - $svnpath =~ s#^/*##; - my $subpool = SVN::Pool::new_default_sub; - my $kind = $svn->{'svn'}->check_path($svnpath,$revision); - return $kind; -} - -sub get_file($$$) { - my($svnpath,$rev,$path) = @_; - - # now get it - my ($name,$mode); - if($opt_d) { - my($req,$res); - - # /svn/!svn/bc/2/django/trunk/django-docs/build.py - my $url=$svn_url->clone(); - $url->path($url->path."/!svn/bc/$rev/$svn_dir$svnpath"); - print "... $path...\n" if $opt_v; - $req = HTTP::Request->new(GET => $url); - $res = $lwp_ua->request($req); - if ($res->is_success) { - my $fh; - ($fh, $name) = tempfile('gitsvn.XXXXXX', - DIR => File::Spec->tmpdir(), UNLINK => 1); - print $fh $res->content; - close($fh) or die "Could not write $name: $!\n"; - } else { - return undef if $res->code == 301; # directory? - die $res->status_line." at $url\n"; - } - $mode = '0644'; # can't obtain mode via direct http request? - } else { - ($name,$mode) = $svn->file("$svnpath",$rev); - return undef unless defined $name; - } - - my $pid = open(my $F, '-|'); - die $! unless defined $pid; - if (!$pid) { - exec("git", "hash-object", "-w", $name) - or die "Cannot create object: $!\n"; - } - my $sha = <$F>; - chomp $sha; - close $F; - unlink $name; - return [$mode, $sha, $path]; -} - -sub get_ignore($$$$$) { - my($new,$old,$rev,$path,$svnpath) = @_; - - return unless $opt_I; - my $name = $svn->ignore("$svnpath",$rev); - if ($path eq '/') { - $path = $opt_I; - } else { - $path = File::Spec->catfile($path,$opt_I); - } - if (defined $name) { - my $pid = open(my $F, '-|'); - die $! unless defined $pid; - if (!$pid) { - exec("git", "hash-object", "-w", $name) - or die "Cannot create object: $!\n"; - } - my $sha = <$F>; - chomp $sha; - close $F; - unlink $name; - push(@$new,['0644',$sha,$path]); - } elsif (defined $old) { - push(@$old,$path); - } -} - -sub project_path($$) -{ - my ($path, $project) = @_; - - $path = "/".$path unless ($path =~ m#^\/#) ; - return $1 if ($path =~ m#^$project\/(.*)$#); - - $path =~ s#\.#\\\.#g; - $path =~ s#\+#\\\+#g; - return "/" if ($project =~ m#^$path.*$#); - - return undef; -} - -sub split_path($$) { - my($rev,$path) = @_; - my $branch; - - if($path =~ s#^/\Q$tag_name\E/([^/]+)/?##) { - $branch = "/$1"; - } elsif($path =~ s#^/\Q$trunk_name\E/?##) { - $branch = "/"; - } elsif($path =~ s#^/\Q$branch_name\E/([^/]+)/?##) { - $branch = $1; - } else { - my %no_error = ( - "/" => 1, - "/$tag_name" => 1, - "/$branch_name" => 1 - ); - print STDERR "$rev: Unrecognized path: $path\n" unless (defined $no_error{$path}); - return () - } - if ($path eq "") { - $path = "/"; - } elsif ($project_name) { - $path = project_path($path, $project_name); - } - return ($branch,$path); -} - -sub branch_rev($$) { - - my ($srcbranch,$uptorev) = @_; - - my $bbranches = $branches{$srcbranch}; - my @revs = reverse sort { ($a eq 'LAST' ? 0 : $a) <=> ($b eq 'LAST' ? 0 : $b) } keys %$bbranches; - my $therev; - foreach my $arev(@revs) { - next if ($arev eq 'LAST'); - if ($arev <= $uptorev) { - $therev = $arev; - last; - } - } - return $therev; -} - -sub expand_svndir($$$); - -sub expand_svndir($$$) -{ - my ($svnpath, $rev, $path) = @_; - my @list; - get_ignore(\@list, undef, $rev, $path, $svnpath); - my $dirents = $svn->dir_list($svnpath, $rev); - foreach my $p(keys %$dirents) { - my $kind = node_kind($svnpath.'/'.$p, $rev); - if ($kind eq $SVN::Node::file) { - my $f = get_file($svnpath.'/'.$p, $rev, $path.'/'.$p); - push(@list, $f) if $f; - } elsif ($kind eq $SVN::Node::dir) { - push(@list, - expand_svndir($svnpath.'/'.$p, $rev, $path.'/'.$p)); - } - } - return @list; -} - -sub copy_path($$$$$$$$) { - # Somebody copied a whole subdirectory. - # We need to find the index entries from the old version which the - # SVN log entry points to, and add them to the new place. - - my($newrev,$newbranch,$path,$oldpath,$rev,$node_kind,$new,$parents) = @_; - - my($srcbranch,$srcpath) = split_path($rev,$oldpath); - unless(defined $srcbranch && defined $srcpath) { - print "Path not found when copying from $oldpath @ $rev.\n". - "Will try to copy from original SVN location...\n" - if $opt_v; - push (@$new, expand_svndir($oldpath, $rev, $path)); - return; - } - my $therev = branch_rev($srcbranch, $rev); - my $gitrev = $branches{$srcbranch}{$therev}; - unless($gitrev) { - print STDERR "$newrev:$newbranch: could not find $oldpath \@ $rev\n"; - return; - } - if ($srcbranch ne $newbranch) { - push(@$parents, $branches{$srcbranch}{'LAST'}); - } - print "$newrev:$newbranch:$path: copying from $srcbranch:$srcpath @ $rev\n" if $opt_v; - if ($node_kind eq $SVN::Node::dir) { - $srcpath =~ s#/*$#/#; - } - - my $pid = open my $f,'-|'; - die $! unless defined $pid; - if (!$pid) { - exec("git","ls-tree","-r","-z",$gitrev,$srcpath) - or die $!; - } - local $/ = "\0"; - while(<$f>) { - chomp; - my($m,$p) = split(/\t/,$_,2); - my($mode,$type,$sha1) = split(/ /,$m); - next if $type ne "blob"; - if ($node_kind eq $SVN::Node::dir) { - $p = $path . substr($p,length($srcpath)-1); - } else { - $p = $path; - } - push(@$new,[$mode,$sha1,$p]); - } - close($f) or - print STDERR "$newrev:$newbranch: could not list files in $oldpath \@ $rev\n"; -} - -sub commit { - my($branch, $changed_paths, $revision, $author, $date, $message) = @_; - my($committer_name,$committer_email,$dest); - my($author_name,$author_email); - my(@old,@new,@parents); - - if (not defined $author or $author eq "") { - $committer_name = $committer_email = "unknown"; - } elsif (defined $users_file) { - die "User $author is not listed in $users_file\n" - unless exists $users{$author}; - ($committer_name,$committer_email) = @{$users{$author}}; - } elsif ($author =~ /^(.*?)\s+<(.*)>$/) { - ($committer_name, $committer_email) = ($1, $2); - } else { - $author =~ s/^<(.*)>$/$1/; - $committer_name = $committer_email = $author; - } - - if ($opt_F && $message =~ /From:\s+(.*?)\s+<(.*)>\s*\n/) { - ($author_name, $author_email) = ($1, $2); - print "Author from From: $1 <$2>\n" if ($opt_v);; - } elsif ($opt_S && $message =~ /Signed-off-by:\s+(.*?)\s+<(.*)>\s*\n/) { - ($author_name, $author_email) = ($1, $2); - print "Author from Signed-off-by: $1 <$2>\n" if ($opt_v);; - } else { - $author_name = $committer_name; - $author_email = $committer_email; - } - - $date = pdate($date); - - my $tag; - my $parent; - if($branch eq "/") { # trunk - $parent = $opt_o; - } elsif($branch =~ m#^/(.+)#) { # tag - $tag = 1; - $parent = $1; - } else { # "normal" branch - # nothing to do - $parent = $branch; - } - $dest = $parent; - - my $prev = $changed_paths->{"/"}; - if($prev and $prev->[0] eq "A") { - delete $changed_paths->{"/"}; - my $oldpath = $prev->[1]; - my $rev; - if(defined $oldpath) { - my $p; - ($parent,$p) = split_path($revision,$oldpath); - if(defined $parent) { - if($parent eq "/") { - $parent = $opt_o; - } else { - $parent =~ s#^/##; # if it's a tag - } - } - } else { - $parent = undef; - } - } - - my $rev; - if($revision > $opt_s and defined $parent) { - open(H,'-|',"git","rev-parse","--verify",$parent); - $rev = <H>; - close(H) or do { - print STDERR "$revision: cannot find commit '$parent'!\n"; - return; - }; - chop $rev; - if(length($rev) != 40) { - print STDERR "$revision: cannot find commit '$parent'!\n"; - return; - } - $rev = $branches{($parent eq $opt_o) ? "/" : $parent}{"LAST"}; - if($revision != $opt_s and not $rev) { - print STDERR "$revision: do not know ancestor for '$parent'!\n"; - return; - } - } else { - $rev = undef; - } - -# if($prev and $prev->[0] eq "A") { -# if(not $tag) { -# unless(open(H,"> $git_dir/refs/heads/$branch")) { -# print STDERR "$revision: Could not create branch $branch: $!\n"; -# $state=11; -# next; -# } -# print H "$rev\n" -# or die "Could not write branch $branch: $!"; -# close(H) -# or die "Could not write branch $branch: $!"; -# } -# } - if(not defined $rev) { - unlink($git_index); - } elsif ($rev ne $last_rev) { - print "Switching from $last_rev to $rev ($branch)\n" if $opt_v; - system("git", "read-tree", $rev); - die "read-tree failed for $rev: $?\n" if $?; - $last_rev = $rev; - } - - push (@parents, $rev) if defined $rev; - - my $cid; - if($tag and not %$changed_paths) { - $cid = $rev; - } else { - my @paths = sort keys %$changed_paths; - foreach my $path(@paths) { - my $action = $changed_paths->{$path}; - - if ($action->[0] eq "R") { - # refer to a file/tree in an earlier commit - push(@old,$path); # remove any old stuff - } - if(($action->[0] eq "A") || ($action->[0] eq "R")) { - my $node_kind = node_kind($action->[3], $revision); - if ($node_kind eq $SVN::Node::file) { - my $f = get_file($action->[3], - $revision, $path); - if ($f) { - push(@new,$f) if $f; - } else { - my $opath = $action->[3]; - print STDERR "$revision: $branch: could not fetch '$opath'\n"; - } - } elsif ($node_kind eq $SVN::Node::dir) { - if($action->[1]) { - copy_path($revision, $branch, - $path, $action->[1], - $action->[2], $node_kind, - \@new, \@parents); - } else { - get_ignore(\@new, \@old, $revision, - $path, $action->[3]); - } - } - } elsif ($action->[0] eq "D") { - push(@old,$path); - } elsif ($action->[0] eq "M") { - my $node_kind = node_kind($action->[3], $revision); - if ($node_kind eq $SVN::Node::file) { - my $f = get_file($action->[3], - $revision, $path); - push(@new,$f) if $f; - } elsif ($node_kind eq $SVN::Node::dir) { - get_ignore(\@new, \@old, $revision, - $path, $action->[3]); - } - } else { - die "$revision: unknown action '".$action->[0]."' for $path\n"; - } - } - - while(@old) { - my @o1; - if(@old > 55) { - @o1 = splice(@old,0,50); - } else { - @o1 = @old; - @old = (); - } - my $pid = open my $F, "-|"; - die "$!" unless defined $pid; - if (!$pid) { - exec("git", "ls-files", "-z", @o1) or die $!; - } - @o1 = (); - local $/ = "\0"; - while(<$F>) { - chomp; - push(@o1,$_); - } - close($F); - - while(@o1) { - my @o2; - if(@o1 > 55) { - @o2 = splice(@o1,0,50); - } else { - @o2 = @o1; - @o1 = (); - } - system("git","update-index","--force-remove","--",@o2); - die "Cannot remove files: $?\n" if $?; - } - } - while(@new) { - my @n2; - if(@new > 12) { - @n2 = splice(@new,0,10); - } else { - @n2 = @new; - @new = (); - } - system("git","update-index","--add", - (map { ('--cacheinfo', @$_) } @n2)); - die "Cannot add files: $?\n" if $?; - } - - my $pid = open(C,"-|"); - die "Cannot fork: $!" unless defined $pid; - unless($pid) { - exec("git","write-tree"); - die "Cannot exec git-write-tree: $!\n"; - } - chomp(my $tree = <C>); - length($tree) == 40 - or die "Cannot get tree id ($tree): $!\n"; - close(C) - or die "Error running git-write-tree: $?\n"; - print "Tree ID $tree\n" if $opt_v; - - my $pr = IO::Pipe->new() or die "Cannot open pipe: $!\n"; - my $pw = IO::Pipe->new() or die "Cannot open pipe: $!\n"; - $pid = fork(); - die "Fork: $!\n" unless defined $pid; - unless($pid) { - $pr->writer(); - $pw->reader(); - open(OUT,">&STDOUT"); - dup2($pw->fileno(),0); - dup2($pr->fileno(),1); - $pr->close(); - $pw->close(); - - my @par = (); - - # loose detection of merges - # based on the commit msg - foreach my $rx (@mergerx) { - if ($message =~ $rx) { - my $mparent = $1; - if ($mparent eq 'HEAD') { $mparent = $opt_o }; - if ( -e "$git_dir/refs/heads/$mparent") { - $mparent = get_headref($mparent, $git_dir); - push (@parents, $mparent); - print OUT "Merge parent branch: $mparent\n" if $opt_v; - } - } - } - my %seen_parents = (); - my @unique_parents = grep { ! $seen_parents{$_} ++ } @parents; - foreach my $bparent (@unique_parents) { - push @par, '-p', $bparent; - print OUT "Merge parent branch: $bparent\n" if $opt_v; - } - - exec("env", - "GIT_AUTHOR_NAME=$author_name", - "GIT_AUTHOR_EMAIL=$author_email", - "GIT_AUTHOR_DATE=".strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date)), - "GIT_COMMITTER_NAME=$committer_name", - "GIT_COMMITTER_EMAIL=$committer_email", - "GIT_COMMITTER_DATE=".strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date)), - "git", "commit-tree", $tree,@par); - die "Cannot exec git-commit-tree: $!\n"; - } - $pw->writer(); - $pr->reader(); - - $message =~ s/[\s\n]+\z//; - $message = "r$revision: $message" if $opt_r; - - print $pw "$message\n" - or die "Error writing to git-commit-tree: $!\n"; - $pw->close(); - - print "Committed change $revision:$branch ".strftime("%Y-%m-%d %H:%M:%S",gmtime($date)).")\n" if $opt_v; - chomp($cid = <$pr>); - length($cid) == 40 - or die "Cannot get commit id ($cid): $!\n"; - print "Commit ID $cid\n" if $opt_v; - $pr->close(); - - waitpid($pid,0); - die "Error running git-commit-tree: $?\n" if $?; - } - - if (not defined $cid) { - $cid = $branches{"/"}{"LAST"}; - } - - if(not defined $dest) { - print "... no known parent\n" if $opt_v; - } elsif(not $tag) { - print "Writing to refs/heads/$dest\n" if $opt_v; - open(C,">$git_dir/refs/heads/$dest") and - print C ("$cid\n") and - close(C) - or die "Cannot write branch $dest for update: $!\n"; - } - - if ($tag) { - $last_rev = "-" if %$changed_paths; - # the tag was 'complex', i.e. did not refer to a "real" revision - - $dest =~ tr/_/\./ if $opt_u; - - system('git', 'tag', '-f', $dest, $cid) == 0 - or die "Cannot create tag $dest: $!\n"; - - print "Created tag '$dest' on '$branch'\n" if $opt_v; - } - $branches{$branch}{"LAST"} = $cid; - $branches{$branch}{$revision} = $cid; - $last_rev = $cid; - print BRANCHES "$revision $branch $cid\n"; - print "DONE: $revision $dest $cid\n" if $opt_v; -} - -sub commit_all { - # Recursive use of the SVN connection does not work - local $svn = $svn2; - - my ($changed_paths, $revision, $author, $date, $message) = @_; - my %p; - while(my($path,$action) = each %$changed_paths) { - $p{$path} = [ $action->action,$action->copyfrom_path, $action->copyfrom_rev, $path ]; - } - $changed_paths = \%p; - - my %done; - my @col; - my $pref; - my $branch; - - while(my($path,$action) = each %$changed_paths) { - ($branch,$path) = split_path($revision,$path); - next if not defined $branch; - next if not defined $path; - $done{$branch}{$path} = $action; - } - while(($branch,$changed_paths) = each %done) { - commit($branch, $changed_paths, $revision, $author, $date, $message); - } -} - -$opt_l = $svn->{'maxrev'} if not defined $opt_l or $opt_l > $svn->{'maxrev'}; - -if ($opt_l < $current_rev) { - print "Up to date: no new revisions to fetch!\n" if $opt_v; - unlink("$git_dir/SVN2GIT_HEAD"); - exit; -} - -print "Processing from $current_rev to $opt_l ...\n" if $opt_v; - -my $from_rev; -my $to_rev = $current_rev - 1; - -my $subpool = SVN::Pool::new_default_sub; -while ($to_rev < $opt_l) { - $subpool->clear; - $from_rev = $to_rev + 1; - $to_rev = $from_rev + $repack_after; - $to_rev = $opt_l if $opt_l < $to_rev; - print "Fetching from $from_rev to $to_rev ...\n" if $opt_v; - $svn->{'svn'}->get_log("",$from_rev,$to_rev,0,1,1,\&commit_all); - my $pid = fork(); - die "Fork: $!\n" unless defined $pid; - unless($pid) { - exec("git", "repack", "-d") - or die "Cannot repack: $!\n"; - } - waitpid($pid, 0); -} - - -unlink($git_index); - -if (defined $orig_git_index) { - $ENV{GIT_INDEX_FILE} = $orig_git_index; -} else { - delete $ENV{GIT_INDEX_FILE}; -} - -# Now switch back to the branch we were in before all of this happened -if($orig_branch) { - print "DONE\n" if $opt_v and (not defined $opt_l or $opt_l > 0); - system("cp","$git_dir/refs/heads/$opt_o","$git_dir/refs/heads/master") - if $forward_master; - unless ($opt_i) { - system('git', 'read-tree', '-m', '-u', 'SVN2GIT_HEAD', 'HEAD'); - die "read-tree failed: $?\n" if $?; - } -} else { - $orig_branch = "master"; - print "DONE; creating $orig_branch branch\n" if $opt_v and (not defined $opt_l or $opt_l > 0); - system("cp","$git_dir/refs/heads/$opt_o","$git_dir/refs/heads/master") - unless -f "$git_dir/refs/heads/master"; - system('git', 'update-ref', 'HEAD', "$orig_branch"); - unless ($opt_i) { - system('git checkout'); - die "checkout failed: $?\n" if $?; - } -} -unlink("$git_dir/SVN2GIT_HEAD"); -close(BRANCHES); diff --git a/contrib/examples/git-svnimport.txt b/contrib/examples/git-svnimport.txt deleted file mode 100644 index 3f0a9c33b5..0000000000 --- a/contrib/examples/git-svnimport.txt +++ /dev/null @@ -1,179 +0,0 @@ -git-svnimport(1) -================ -v0.1, July 2005 - -NAME ----- -git-svnimport - Import a SVN repository into git - - -SYNOPSIS --------- -[verse] -'git-svnimport' [ -o <branch-for-HEAD> ] [ -h ] [ -v ] [ -d | -D ] - [ -C <GIT_repository> ] [ -i ] [ -u ] [-l limit_rev] - [ -b branch_subdir ] [ -T trunk_subdir ] [ -t tag_subdir ] - [ -s start_chg ] [ -m ] [ -r ] [ -M regex ] - [ -I <ignorefile_name> ] [ -A <author_file> ] - [ -R <repack_each_revs>] [ -P <path_from_trunk> ] - <SVN_repository_URL> [ <path> ] - - -DESCRIPTION ------------ -Imports a SVN repository into git. It will either create a new -repository, or incrementally import into an existing one. - -SVN access is done by the SVN::Perl module. - -git-svnimport assumes that SVN repositories are organized into one -"trunk" directory where the main development happens, "branches/FOO" -directories for branches, and "/tags/FOO" directories for tags. -Other subdirectories are ignored. - -git-svnimport creates a file ".git/svn2git", which is required for -incremental SVN imports. - -OPTIONS -------- --C <target-dir>:: - The GIT repository to import to. If the directory doesn't - exist, it will be created. Default is the current directory. - --s <start_rev>:: - Start importing at this SVN change number. The default is 1. -+ -When importing incrementally, you might need to edit the .git/svn2git file. - --i:: - Import-only: don't perform a checkout after importing. This option - ensures the working directory and index remain untouched and will - not create them if they do not exist. - --T <trunk_subdir>:: - Name the SVN trunk. Default "trunk". - --t <tag_subdir>:: - Name the SVN subdirectory for tags. Default "tags". - --b <branch_subdir>:: - Name the SVN subdirectory for branches. Default "branches". - --o <branch-for-HEAD>:: - The 'trunk' branch from SVN is imported to the 'origin' branch within - the git repository. Use this option if you want to import into a - different branch. - --r:: - Prepend 'rX: ' to commit messages, where X is the imported - subversion revision. - --u:: - Replace underscores in tag names with periods. - --I <ignorefile_name>:: - Import the svn:ignore directory property to files with this - name in each directory. (The Subversion and GIT ignore - syntaxes are similar enough that using the Subversion patterns - directly with "-I .gitignore" will almost always just work.) - --A <author_file>:: - Read a file with lines on the form -+ ------- - username = User's Full Name <email@addr.es> - ------- -+ -and use "User's Full Name <email@addr.es>" as the GIT -author and committer for Subversion commits made by -"username". If encountering a commit made by a user not in the -list, abort. -+ -For convenience, this data is saved to $GIT_DIR/svn-authors -each time the -A option is provided, and read from that same -file each time git-svnimport is run with an existing GIT -repository without -A. - --m:: - Attempt to detect merges based on the commit message. This option - will enable default regexes that try to capture the name source - branch name from the commit message. - --M <regex>:: - Attempt to detect merges based on the commit message with a custom - regex. It can be used with -m to also see the default regexes. - You must escape forward slashes. - --l <max_rev>:: - Specify a maximum revision number to pull. -+ -Formerly, this option controlled how many revisions to pull, -due to SVN memory leaks. (These have been worked around.) - --R <repack_each_revs>:: - Specify how often git repository should be repacked. -+ -The default value is 1000. git-svnimport will do imports in chunks of 1000 -revisions, after each chunk the git repository will be repacked. To disable -this behavior specify some large value here which is greater than the number of -revisions to import. - --P <path_from_trunk>:: - Partial import of the SVN tree. -+ -By default, the whole tree on the SVN trunk (/trunk) is imported. -'-P my/proj' will import starting only from '/trunk/my/proj'. -This option is useful when you want to import one project from a -svn repo which hosts multiple projects under the same trunk. - --v:: - Verbosity: let 'svnimport' report what it is doing. - --d:: - Use direct HTTP requests if possible. The "<path>" argument is used - only for retrieving the SVN logs; the path to the contents is - included in the SVN log. - --D:: - Use direct HTTP requests if possible. The "<path>" argument is used - for retrieving the logs, as well as for the contents. -+ -There's no safe way to automatically find out which of these options to -use, so you need to try both. Usually, the one that's wrong will die -with a 40x error pretty quickly. - -<SVN_repository_URL>:: - The URL of the SVN module you want to import. For local - repositories, use "file:///absolute/path". -+ -If you're using the "-d" or "-D" option, this is the URL of the SVN -repository itself; it usually ends in "/svn". - -<path>:: - The path to the module you want to check out. - --h:: - Print a short usage message and exit. - -OUTPUT ------- -If '-v' is specified, the script reports what it is doing. - -Otherwise, success is indicated the Unix way, i.e. by simply exiting with -a zero exit status. - -Author ------- -Written by Matthias Urlichs <smurf@smurf.noris.de>, with help from -various participants of the git-list <git@vger.kernel.org>. - -Based on a cvs2git script by the same author. - -Documentation --------------- -Documentation by Matthias Urlichs <smurf@smurf.noris.de>. - -GIT ---- -Part of the linkgit:git[7] suite diff --git a/contrib/examples/git-tag.sh b/contrib/examples/git-tag.sh deleted file mode 100755 index 1bd8f3c58d..0000000000 --- a/contrib/examples/git-tag.sh +++ /dev/null @@ -1,205 +0,0 @@ -#!/bin/sh -# Copyright (c) 2005 Linus Torvalds - -USAGE='[-n [<num>]] -l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg>] <tagname> [<head>]' -SUBDIRECTORY_OK='Yes' -. git-sh-setup - -message_given= -annotate= -signed= -force= -message= -username= -list= -verify= -LINES=0 -while test $# != 0 -do - case "$1" in - -a) - annotate=1 - shift - ;; - -s) - annotate=1 - signed=1 - shift - ;; - -f) - force=1 - shift - ;; - -n) - case "$#,$2" in - 1,* | *,-*) - LINES=1 # no argument - ;; - *) shift - LINES=$(expr "$1" : '\([0-9]*\)') - [ -z "$LINES" ] && LINES=1 # 1 line is default when -n is used - ;; - esac - shift - ;; - -l) - list=1 - shift - case $# in - 0) PATTERN= - ;; - *) - PATTERN="$1" # select tags by shell pattern, not re - shift - ;; - esac - git rev-parse --symbolic --tags | sort | - while read TAG - do - case "$TAG" in - *$PATTERN*) ;; - *) continue ;; - esac - [ "$LINES" -le 0 ] && { echo "$TAG"; continue ;} - OBJTYPE=$(git cat-file -t "$TAG") - case $OBJTYPE in - tag) - ANNOTATION=$(git cat-file tag "$TAG" | - sed -e '1,/^$/d' | - sed -n -e " - /^-----BEGIN PGP SIGNATURE-----\$/q - 2,\$s/^/ / - p - ${LINES}q - ") - printf "%-15s %s\n" "$TAG" "$ANNOTATION" - ;; - *) echo "$TAG" - ;; - esac - done - ;; - -m) - annotate=1 - shift - message="$1" - if test "$#" = "0"; then - die "error: option -m needs an argument" - else - message="$1" - message_given=1 - shift - fi - ;; - -F) - annotate=1 - shift - if test "$#" = "0"; then - die "error: option -F needs an argument" - else - message="$(cat "$1")" - message_given=1 - shift - fi - ;; - -u) - annotate=1 - signed=1 - shift - if test "$#" = "0"; then - die "error: option -u needs an argument" - else - username="$1" - shift - fi - ;; - -d) - shift - had_error=0 - for tag - do - cur=$(git show-ref --verify --hash -- "refs/tags/$tag") || { - echo >&2 "Seriously, what tag are you talking about?" - had_error=1 - continue - } - git update-ref -m 'tag: delete' -d "refs/tags/$tag" "$cur" || { - had_error=1 - continue - } - echo "Deleted tag $tag." - done - exit $had_error - ;; - -v) - shift - tag_name="$1" - tag=$(git show-ref --verify --hash -- "refs/tags/$tag_name") || - die "Seriously, what tag are you talking about?" - git-verify-tag -v "$tag" - exit $? - ;; - -*) - usage - ;; - *) - break - ;; - esac -done - -[ -n "$list" ] && exit 0 - -name="$1" -[ "$name" ] || usage -prev=0000000000000000000000000000000000000000 -if git show-ref --verify --quiet -- "refs/tags/$name" -then - test -n "$force" || die "tag '$name' already exists" - prev=$(git rev-parse "refs/tags/$name") -fi -shift -git check-ref-format "tags/$name" || - die "we do not like '$name' as a tag name." - -object=$(git rev-parse --verify --default HEAD "$@") || exit 1 -type=$(git cat-file -t $object) || exit 1 -tagger=$(git var GIT_COMMITTER_IDENT) || exit 1 - -test -n "$username" || - username=$(git config user.signingkey) || - username=$(expr "z$tagger" : 'z\(.*>\)') - -trap 'rm -f "$GIT_DIR"/TAG_TMP* "$GIT_DIR"/TAG_FINALMSG "$GIT_DIR"/TAG_EDITMSG' 0 - -if [ "$annotate" ]; then - if [ -z "$message_given" ]; then - ( echo "#" - echo "# Write a tag message" - echo "#" ) > "$GIT_DIR"/TAG_EDITMSG - git_editor "$GIT_DIR"/TAG_EDITMSG || exit - else - printf '%s\n' "$message" >"$GIT_DIR"/TAG_EDITMSG - fi - - grep -v '^#' <"$GIT_DIR"/TAG_EDITMSG | - git stripspace >"$GIT_DIR"/TAG_FINALMSG - - [ -s "$GIT_DIR"/TAG_FINALMSG -o -n "$message_given" ] || { - echo >&2 "No tag message?" - exit 1 - } - - ( printf 'object %s\ntype %s\ntag %s\ntagger %s\n\n' \ - "$object" "$type" "$name" "$tagger"; - cat "$GIT_DIR"/TAG_FINALMSG ) >"$GIT_DIR"/TAG_TMP - rm -f "$GIT_DIR"/TAG_TMP.asc "$GIT_DIR"/TAG_FINALMSG - if [ "$signed" ]; then - gpg -bsa -u "$username" "$GIT_DIR"/TAG_TMP && - cat "$GIT_DIR"/TAG_TMP.asc >>"$GIT_DIR"/TAG_TMP || - die "failed to sign the tag with GPG." - fi - object=$(git-mktag < "$GIT_DIR"/TAG_TMP) -fi - -git update-ref "refs/tags/$name" "$object" "$prev" diff --git a/contrib/examples/git-verify-tag.sh b/contrib/examples/git-verify-tag.sh deleted file mode 100755 index 0902a5c21a..0000000000 --- a/contrib/examples/git-verify-tag.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh - -USAGE='<tag>' -SUBDIRECTORY_OK='Yes' -. git-sh-setup - -verbose= -while test $# != 0 -do - case "$1" in - -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose) - verbose=t ;; - *) - break ;; - esac - shift -done - -if [ "$#" != "1" ] -then - usage -fi - -type="$(git cat-file -t "$1" 2>/dev/null)" || - die "$1: no such object." - -test "$type" = tag || - die "$1: cannot verify a non-tag object of type $type." - -case "$verbose" in -t) - git cat-file -p "$1" | - sed -n -e '/^-----BEGIN PGP SIGNATURE-----/q' -e p - ;; -esac - -trap 'rm -f "$GIT_DIR/.tmp-vtag"' 0 - -git cat-file tag "$1" >"$GIT_DIR/.tmp-vtag" || exit 1 -sed -n -e ' - /^-----BEGIN PGP SIGNATURE-----$/q - p -' <"$GIT_DIR/.tmp-vtag" | -gpg --verify "$GIT_DIR/.tmp-vtag" - || exit 1 -rm -f "$GIT_DIR/.tmp-vtag" diff --git a/contrib/examples/git-whatchanged.sh b/contrib/examples/git-whatchanged.sh deleted file mode 100755 index 2edbdc6d99..0000000000 --- a/contrib/examples/git-whatchanged.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh - -USAGE='[-p] [--max-count=<n>] [<since>..<limit>] [--pretty=<format>] [-m] [git-diff-tree options] [git-rev-list options]' -SUBDIRECTORY_OK='Yes' -. git-sh-setup - -diff_tree_flags=$(git-rev-parse --sq --no-revs --flags "$@") || exit -case "$0" in -*whatchanged) - count= - test -z "$diff_tree_flags" && - diff_tree_flags=$(git config --get whatchanged.difftree) - diff_tree_default_flags='-c -M --abbrev' ;; -*show) - count=-n1 - test -z "$diff_tree_flags" && - diff_tree_flags=$(git config --get show.difftree) - diff_tree_default_flags='--cc --always' ;; -esac -test -z "$diff_tree_flags" && - diff_tree_flags="$diff_tree_default_flags" - -rev_list_args=$(git-rev-parse --sq --default HEAD --revs-only "$@") && -diff_tree_args=$(git-rev-parse --sq --no-revs --no-flags "$@") && - -eval "git-rev-list $count $rev_list_args" | -eval "git-diff-tree --stdin --pretty -r $diff_tree_flags $diff_tree_args" | -LESS="$LESS -S" ${PAGER:-less} diff --git a/contrib/hooks/pre-auto-gc-battery b/contrib/hooks/pre-auto-gc-battery index 6a2cdebdb7..7ba78c4dff 100755 --- a/contrib/hooks/pre-auto-gc-battery +++ b/contrib/hooks/pre-auto-gc-battery @@ -17,7 +17,7 @@ # ln -sf /usr/share/git-core/contrib/hooks/pre-auto-gc-battery \ # hooks/pre-auto-gc -if test -x /sbin/on_ac_power && /sbin/on_ac_power +if test -x /sbin/on_ac_power && (/sbin/on_ac_power;test $? -ne 1) then exit 0 elif test "$(cat /sys/class/power_supply/AC/online 2>/dev/null)" = 1 diff --git a/contrib/mw-to-git/Makefile b/contrib/mw-to-git/Makefile index a4b6f7a2cd..4e603512a3 100644 --- a/contrib/mw-to-git/Makefile +++ b/contrib/mw-to-git/Makefile @@ -21,8 +21,9 @@ HERE=contrib/mw-to-git/ INSTALL = install SCRIPT_PERL_FULL=$(patsubst %,$(HERE)/%,$(SCRIPT_PERL)) -INSTLIBDIR=$(shell $(MAKE) -C $(GIT_ROOT_DIR)/perl \ - -s --no-print-directory instlibdir) +INSTLIBDIR=$(shell $(MAKE) -C $(GIT_ROOT_DIR)/ \ + -s --no-print-directory prefix=$(prefix) \ + perllibdir=$(perllibdir) perllibdir) DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) INSTLIBDIR_SQ = $(subst ','\'',$(INSTLIBDIR)) diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh index dec085a235..d3f39a862a 100755 --- a/contrib/subtree/git-subtree.sh +++ b/contrib/subtree/git-subtree.sh @@ -297,7 +297,7 @@ find_latest_squash () { main= sub= git log --grep="^git-subtree-dir: $dir/*\$" \ - --pretty=format:'START %H%n%s%n%n%b%nEND%n' HEAD | + --no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' HEAD | while read a b junk do debug "$a $b $junk" @@ -341,7 +341,7 @@ find_existing_splits () { main= sub= git log --grep="^git-subtree-dir: $dir/*\$" \ - --pretty=format:'START %H%n%s%n%n%b%nEND%n' $revs | + --no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' $revs | while read a b junk do case "$a" in @@ -382,7 +382,7 @@ copy_commit () { # We're going to set some environment vars here, so # do it in a subshell to get rid of them safely later debug copy_commit "{$1}" "{$2}" "{$3}" - git log -1 --pretty=format:'%an%n%ae%n%aD%n%cn%n%ce%n%cD%n%B' "$1" | + git log -1 --no-show-signature --pretty=format:'%an%n%ae%n%aD%n%cn%n%ce%n%cD%n%B' "$1" | ( read GIT_AUTHOR_NAME read GIT_AUTHOR_EMAIL @@ -462,8 +462,8 @@ squash_msg () { oldsub_short=$(git rev-parse --short "$oldsub") echo "Squashed '$dir/' changes from $oldsub_short..$newsub_short" echo - git log --pretty=tformat:'%h %s' "$oldsub..$newsub" - git log --pretty=tformat:'REVERT: %h %s' "$newsub..$oldsub" + git log --no-show-signature --pretty=tformat:'%h %s' "$oldsub..$newsub" + git log --no-show-signature --pretty=tformat:'REVERT: %h %s' "$newsub..$oldsub" else echo "Squashed '$dir/' content from commit $newsub_short" fi @@ -475,7 +475,7 @@ squash_msg () { toptree_for_commit () { commit="$1" - git log -1 --pretty=format:'%T' "$commit" -- || exit $? + git rev-parse --verify "$commit^{tree}" || exit $? } subtree_for_commit () { diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt index 60d76cdddf..352deda69d 100644 --- a/contrib/subtree/git-subtree.txt +++ b/contrib/subtree/git-subtree.txt @@ -28,7 +28,7 @@ as a subdirectory of your application. Subtrees are not to be confused with submodules, which are meant for the same task. Unlike submodules, subtrees do not need any special -constructions (like .gitmodule files or gitlinks) be present in +constructions (like .gitmodules files or gitlinks) be present in your repository, and do not force end-users of your repository to do anything special or to understand how subtrees work. A subtree is just a subdirectory that can be diff --git a/contrib/update-unicode/README b/contrib/update-unicode/README index b9e2fc8540..151a197041 100644 --- a/contrib/update-unicode/README +++ b/contrib/update-unicode/README @@ -1,10 +1,10 @@ TL;DR: Run update_unicode.sh after the publication of a new Unicode -standard and commit the resulting unicode_widths.h file. +standard and commit the resulting unicode-widths.h file. The long version ================ -The Git source code ships the file unicode_widths.h which contains +The Git source code ships the file unicode-widths.h which contains tables of zero and double width Unicode code points, respectively. These tables are generated using update_unicode.sh in this directory. update_unicode.sh itself uses a third-party tool, uniset, to query two @@ -16,5 +16,5 @@ This requires a current-ish version of autoconf (2.69 works per December On each run, update_unicode.sh checks whether more recent Unicode data files are available from the Unicode consortium, and rebuilds the header -unicode_widths.h with the new data. The new header can then be +unicode-widths.h with the new data. The new header can then be committed. diff --git a/contrib/update-unicode/update_unicode.sh b/contrib/update-unicode/update_unicode.sh index e05db92d3f..aa90865bef 100755 --- a/contrib/update-unicode/update_unicode.sh +++ b/contrib/update-unicode/update_unicode.sh @@ -6,7 +6,7 @@ #Cf Format a format control character # cd "$(dirname "$0")" -UNICODEWIDTH_H=$(git rev-parse --show-toplevel)/unicode_width.h +UNICODEWIDTH_H=$(git rev-parse --show-toplevel)/unicode-width.h wget -N http://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt \ http://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt && |