--------
[verse]
'git-pack-objects' [-q] [--no-reuse-delta] [--delta-base-offset] [--non-empty]
- [--local] [--incremental] [--window=N] [--depth=N]
+ [--local] [--incremental] [--window=N] [--depth=N] [--all-progress]
[--revs [--unpacked | --all]*] [--stdout | base-name] < object-list
--- /dev/null
+git-pack-refs(1)
+================
+
+NAME
+----
+git-pack-refs - Pack heads and tags for efficient repository access
+
+SYNOPSIS
+--------
+'git-pack-refs' [--all] [--prune]
+
+DESCRIPTION
+-----------
+
+Traditionally, tips of branches and tags (collectively known as
+'refs') were stored one file per ref under `$GIT_DIR/refs`
+directory. While many branch tips tend to be updated often,
+most tags and some branch tips are never updated. When a
+repository has hundreds or thousands of tags, this
+one-file-per-ref format both wastes storage and hurts
+performance.
+
+This command is used to solve the storage and performance
+problem by stashing the refs in a single file,
+`$GIT_DIR/packed-refs`. When a ref is missing from the
+traditional `$GIT_DIR/refs` hierarchy, it is looked up in this
+file and used if found.
+
+Subsequent updates to branches always creates new file under
+`$GIT_DIR/refs` hierarchy.
+
+OPTIONS
+-------
+
+\--all::
+
+The command by default packs all tags and leaves branch tips
+alone. This is because branches are expected to be actively
+developed and packing their tips does not help performance.
+This option causes branch tips to be packed as well. Useful for
+a repository with many branches of historical interests.
+
+\--prune::
+
+After packing the refs, remove loose refs under `$GIT_DIR/refs`
+hierarchy. This should probably become default.
+
+Author
+------
+Written by Linus Torvalds <torvalds@osdl.org>
+
+GIT
+---
+Part of the gitlink:git[7] suite
D---E---F---G master
------------
-While, starting from the same point, the result of either of the following
-commands:
+The latter form is just a short-hand of `git checkout topic`
+followed by `git rebase master`.
- git-rebase --onto master~1 master
- git-rebase --onto master~1 master topic
+Here is how you would transplant a topic branch based on one
+branch to another, to pretend that you forked the topic branch
+from the latter branch, using `rebase --onto`.
-would be:
+First let's assume your 'topic' is based on branch 'next'.
+For example feature developed in 'topic' depends on some
+functionality which is found in 'next'.
------------
- A'--B'--C' topic
- /
- D---E---F---G master
+ o---o---o---o---o master
+ \
+ o---o---o---o---o next
+ \
+ o---o---o topic
+------------
+
+We would want to make 'topic' forked from branch 'master',
+for example because the functionality 'topic' branch depend on
+got merged into more stable 'master' branch, like this:
+
+------------
+ o---o---o---o---o master
+ | \
+ | o'--o'--o' topic
+ \
+ o---o---o---o---o next
------------
+We can get this using the following command:
+
+ git-rebase --onto master next topic
+
+
+Another example of --onto option is to rebase part of a
+branch. If we have the following situation:
+
+------------
+ H---I---J topicB
+ /
+ E---F---G topicA
+ /
+ A---B---C---D master
+------------
+
+then the command
+
+ git-rebase --onto master topicA topicB
+
+would result in:
+
+------------
+ H'--I'--J' topicB
+ /
+ | E---F---G topicA
+ |/
+ A---B---C---D master
+------------
+
+This is useful when topicB does not depend on topicA.
+
In case of conflict, git-rebase will stop at the first problematic commit
and leave conflict markers in the tree. You can use git diff to locate
the markers (<<<<<<) and make edits to resolve the conflict. For each
gitlink:git-mv[1]::
Move or rename a file, a directory, or a symlink.
+gitlink:git-pack-refs[1]::
+ Pack heads and tags for efficient repository access.
+
gitlink:git-pull[1]::
Fetch from and merge with a remote repository or a local branch.
gitlink:git-show-index[1]::
Displays contents of a pack idx file.
+gitlink:git-show-ref[1]::
+ List references in a local repository.
+
gitlink:git-tar-tree[1]::
Creates a tar archive of the files in the named tree object.
$(patsubst %.py,%,$(SCRIPT_PYTHON)) \
git-cherry-pick git-status git-instaweb
-# The ones that do not have to link with lcrypto, lz nor xdiff.
-SIMPLE_PROGRAMS = \
- git-daemon$X
-
# ... and all the rest that could be moved out of bindir to gitexecdir
PROGRAMS = \
git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \
git-hash-object$X git-index-pack$X git-local-fetch$X \
git-merge-base$X \
+ git-daemon$X \
git-merge-index$X git-mktag$X git-mktree$X git-patch-id$X \
git-peek-remote$X git-receive-pack$X \
git-send-pack$X git-shell$X \
$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
# what 'all' will build and 'install' will install, in gitexecdir
-ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) \
+ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) \
git-merge-recur$X
# Backward compatibility -- to be removed after 1.0
endif
ifdef NEEDS_SOCKET
EXTLIBS += -lsocket
- SIMPLE_LIB += -lsocket
endif
ifdef NEEDS_NSL
EXTLIBS += -lnsl
- SIMPLE_LIB += -lnsl
endif
ifdef NO_D_TYPE_IN_DIRENT
BASIC_CFLAGS += -DNO_D_TYPE_IN_DIRENT
git-%$X: %.o $(GITLIBS)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
-$(SIMPLE_PROGRAMS) : $(LIB_FILE)
-$(SIMPLE_PROGRAMS) : git-%$X : %.o
- $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
- $(LIB_FILE) $(SIMPLE_LIB)
-
ssh-pull.o: ssh-fetch.c
ssh-push.o: ssh-upload.c
git-local-fetch$X: fetch.o
*) echo "no link: $$v";; \
esac ; \
done | sort
+
+### Make sure built-ins do not have dups and listed in git.c
+#
+check-builtins::
+ ./check-builtins.sh
parse_extra_args_fn_t parse_extra;
};
-extern struct archiver archivers[];
-
extern int parse_archive_args(int argc,
const char **argv,
struct archiver *ar);
static int no_add;
static int show_index_info;
static int line_termination = '\n';
-static unsigned long p_context = -1;
+static unsigned long p_context = ULONG_MAX;
static const char apply_usage[] =
"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|error|error-all|strip>] <patch>...";
* then not having oldlines means the patch is creation,
* and not having newlines means the patch is deletion.
*/
- if (patch->is_new < 0 && !oldlines)
+ if (patch->is_new < 0 && !oldlines) {
patch->is_new = 1;
- if (patch->is_delete < 0 && !newlines)
+ patch->old_name = NULL;
+ }
+ if (patch->is_delete < 0 && !newlines) {
patch->is_delete = 1;
+ patch->new_name = NULL;
+ }
}
if (0 < patch->is_new && oldlines)
static const char archive_usage[] = \
"git-archive --format=<fmt> [--prefix=<prefix>/] [--verbose] [<extra>] <tree-ish> [path...]";
-struct archiver archivers[] = {
- {
- .name = "tar",
- .write_archive = write_tar_archive,
- },
- {
- .name = "zip",
- .write_archive = write_zip_archive,
- .parse_extra = parse_extra_zip_args,
- },
+static struct archiver_desc
+{
+ const char *name;
+ write_archive_fn_t write_archive;
+ parse_extra_args_fn_t parse_extra;
+} archivers[] = {
+ { "tar", write_tar_archive, NULL },
+ { "zip", write_zip_archive, parse_extra_zip_args },
};
static int run_remote_archiver(const char *remote, int argc,
for (i = 0; i < ARRAY_SIZE(archivers); i++) {
if (!strcmp(name, archivers[i].name)) {
- memcpy(ar, &archivers[i], sizeof(struct archiver));
+ memset(ar, 0, sizeof(*ar));
+ ar->name = archivers[i].name;
+ ar->write_archive = archivers[i].write_archive;
+ ar->parse_extra = archivers[i].parse_extra;
rv = 0;
break;
}
#include <sys/time.h>
#include <signal.h>
-static const char pack_usage[] = "git-pack-objects [-q] [--no-reuse-delta] [--delta-base-offset] [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] [--revs [--unpacked | --all]*] [--stdout | base-name] <ref-list | <object-list]";
+static const char pack_usage[] = "git-pack-objects [-q] [--no-reuse-delta] [--delta-base-offset] [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] [--all-progress] [--revs [--unpacked | --all]*] [--stdout | base-name] <ref-list | <object-list]";
struct object_entry {
unsigned char sha1[20];
unsigned long offset;
struct pack_header hdr;
unsigned last_percent = 999;
- int do_progress = 0;
+ int do_progress = progress;
- if (!base_name)
+ if (!base_name) {
f = sha1fd(1, "<stdout>");
- else {
+ do_progress >>= 1;
+ }
+ else
f = sha1create("%s-%s.%s", base_name,
sha1_to_hex(object_list_sha1), "pack");
- do_progress = progress;
- }
if (do_progress)
fprintf(stderr, "Writing %d objects.\n", nr_result);
progress = 1;
continue;
}
+ if (!strcmp("--all-progress", arg)) {
+ progress = 2;
+ continue;
+ }
if (!strcmp("--incremental", arg)) {
incremental = 1;
continue;
else {
if (nr_result)
prepare_pack(window, depth);
- if (progress && pack_to_stdout) {
+ if (progress == 1 && pack_to_stdout) {
/* the other end usually displays progress itself */
struct itimerval v = {{0,},};
setitimer(ITIMER_REAL, &v, NULL);
static const char push_usage[] = "git-push [--all] [--tags] [-f | --force] <repository> [<refspec>...]";
-static int all, tags, force, thin = 1;
+static int all, tags, force, thin = 1, verbose;
static const char *execute;
#define BUF_SIZE (2084)
while (dest_refspec_nr--)
argv[dest_argc++] = *dest_refspec++;
argv[dest_argc] = NULL;
+ if (verbose)
+ fprintf(stderr, "Pushing to %s\n", dest);
err = run_command_v(argc, argv);
if (!err)
continue;
i++;
break;
}
+ if (!strcmp(arg, "-v")) {
+ verbose=1;
+ continue;
+ }
+ if (!strncmp(arg, "--repo=", 7)) {
+ repo = arg+7;
+ continue;
+ }
if (!strcmp(arg, "--all")) {
all = 1;
continue;
--- /dev/null
+#!/bin/sh
+
+{
+ cat <<\EOF
+sayIt:
+ $(foreach b,$(BUILT_INS),echo XXX $b YYY;)
+EOF
+ cat Makefile
+} |
+make -f - sayIt 2>/dev/null |
+sed -n -e 's/.*XXX \(.*\) YYY.*/\1/p' |
+sort |
+{
+ bad=0
+ while read builtin
+ do
+ base=`expr "$builtin" : 'git-\(.*\)'`
+ x=`sed -ne 's/.*{ "'$base'", \(cmd_[^, ]*\).*/'$base' \1/p' git.c`
+ if test -z "$x"
+ then
+ echo "$base is builtin but not listed in git.c command list"
+ bad=1
+ fi
+ for sfx in sh perl py
+ do
+ if test -f "$builtin.$sfx"
+ then
+ echo "$base is builtin but $builtin.$sfx still exists"
+ bad=1
+ fi
+ done
+ done
+ exit $bad
+}
}
}
+static inline int iskeychar(int c)
+{
+ return isalnum(c) || c == '-';
+}
+
static int get_value(config_fn_t fn, char *name, unsigned int len)
{
int c;
c = get_next_char();
if (c == EOF)
break;
- if (!isalnum(c))
+ if (!iskeychar(c))
break;
name[len++] = tolower(c);
if (len >= MAXNAME)
return baselen;
if (isspace(c))
return get_extended_base_var(name, baselen, c);
- if (!isalnum(c) && c != '.')
+ if (!iskeychar(c) && c != '.')
return -1;
if (baselen > MAXNAME / 2)
return -1;
dot = 1;
/* Leave the extended basename untouched.. */
if (!dot || i > store.baselen) {
- if (!isalnum(c) || (i == store.baselen+1 && !isalpha(c))) {
+ if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
fprintf(stderr, "invalid key: %s\n", key);
free(store.key);
ret = 1;
# source ~/.git-completion.sh
#
+__gitdir ()
+{
+ echo "${__git_dir:-$(git rev-parse --git-dir 2>/dev/null)}"
+}
+
__git_refs ()
{
- local cmd i is_hash=y
- if [ -d "$1" ]; then
+ local cmd i is_hash=y dir="${1:-$(__gitdir)}"
+ if [ -d "$dir" ]; then
cmd=git-peek-remote
else
cmd=git-ls-remote
fi
- for i in $($cmd "$1" 2>/dev/null); do
+ for i in $($cmd "$dir" 2>/dev/null); do
case "$is_hash,$i" in
y,*) is_hash=n ;;
n,*^{}) is_hash=y ;;
__git_refs2 ()
{
- local cmd i is_hash=y
- if [ -d "$1" ]; then
+ local cmd i is_hash=y dir="${1:-$(__gitdir)}"
+ if [ -d "$dir" ]; then
cmd=git-peek-remote
else
cmd=git-ls-remote
fi
- for i in $($cmd "$1" 2>/dev/null); do
+ for i in $($cmd "$dir" 2>/dev/null); do
case "$is_hash,$i" in
y,*) is_hash=n ;;
n,*^{}) is_hash=y ;;
__git_remotes ()
{
- local i REVERTGLOB=$(shopt -p nullglob)
+ local i ngoff IFS=$'\n' d="$(__gitdir)"
+ shopt -q nullglob || ngoff=1
shopt -s nullglob
- for i in .git/remotes/*; do
- echo ${i#.git/remotes/}
+ for i in "$d/remotes"/*; do
+ echo ${i#$d/remotes/}
+ done
+ [ "$ngoff" ] && shopt -u nullglob
+ for i in $(git --git-dir="$d" repo-config --list); do
+ case "$i" in
+ remote.*.url=*)
+ i="${i#remote.}"
+ echo "${i/.url=*/}"
+ ;;
+ esac
done
- $REVERTGLOB
}
__git_complete_file ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
+ local pfx ls ref cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
?*:*)
- local pfx ls ref="$(echo "$cur" | sed 's,:.*$,,')"
- cur="$(echo "$cur" | sed 's,^.*:,,')"
+ ref="${cur%%:*}"
+ cur="${cur#*:}"
case "$cur" in
?*/*)
- pfx="$(echo "$cur" | sed 's,/[^/]*$,,')"
- cur="$(echo "$cur" | sed 's,^.*/,,')"
+ pfx="${cur%/*}"
+ cur="${cur##*/}"
ls="$ref:$pfx"
pfx="$pfx/"
;;
;;
esac
COMPREPLY=($(compgen -P "$pfx" \
- -W "$(git-ls-tree "$ls" \
+ -W "$(git --git-dir="$(__gitdir)" ls-tree "$ls" \
| sed '/^100... blob /s,^.* ,,
/^040000 tree /{
s,^.* ,,
-- "$cur"))
;;
*)
- COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
+ COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
;;
esac
}
__git_aliases ()
{
- git repo-config --list | grep '^alias\.' \
- | sed -e 's/^alias\.//' -e 's/=.*$//'
+ local i IFS=$'\n'
+ for i in $(git --git-dir="$(__gitdir)" repo-config --list); do
+ case "$i" in
+ alias.*)
+ i="${i#alias.}"
+ echo "${i/=*/}"
+ ;;
+ esac
+ done
}
__git_aliased_command ()
{
- local cmdline=$(git repo-config alias.$1)
+ local word cmdline=$(git --git-dir="$(__gitdir)" \
+ repo-config --get "alias.$1")
for word in $cmdline; do
if [ "${word##-*}" ]; then
echo $word
_git_branch ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
- COMPREPLY=($(compgen -W "-l -f -d -D $(__git_refs .)" -- "$cur"))
+ COMPREPLY=($(compgen -W "-l -f -d -D $(__git_refs)" -- "$cur"))
}
_git_cat_file ()
_git_checkout ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
- COMPREPLY=($(compgen -W "-l -b $(__git_refs .)" -- "$cur"))
+ COMPREPLY=($(compgen -W "-l -b $(__git_refs)" -- "$cur"))
}
_git_diff ()
_git_diff_tree ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
- COMPREPLY=($(compgen -W "-r -p -M $(__git_refs .)" -- "$cur"))
+ COMPREPLY=($(compgen -W "-r -p -M $(__git_refs)" -- "$cur"))
}
_git_fetch ()
*)
case "$cur" in
*:*)
- cur=$(echo "$cur" | sed 's/^.*://')
- COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
+ cur="${cur#*:}"
+ COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
;;
*)
local remote
_git_log ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
+ local pfx cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
+ *...*)
+ pfx="${cur%...*}..."
+ cur="${cur#*...}"
+ COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
+ ;;
*..*)
- local pfx=$(echo "$cur" | sed 's/\.\..*$/../')
- cur=$(echo "$cur" | sed 's/^.*\.\.//')
- COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs .)" -- "$cur"))
+ pfx="${cur%..*}.."
+ cur="${cur#*..}"
+ COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
;;
*)
- COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
+ COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
;;
esac
}
_git_merge_base ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
- COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
+ COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
}
_git_pull ()
git-push) remote="${COMP_WORDS[1]}" ;;
git) remote="${COMP_WORDS[2]}" ;;
esac
- cur=$(echo "$cur" | sed 's/^.*://')
+ cur="${cur#*:}"
COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
;;
*)
- COMPREPLY=($(compgen -W "$(__git_refs2 .)" -- "$cur"))
+ COMPREPLY=($(compgen -W "$(__git_refs2)" -- "$cur"))
;;
esac
;;
esac
}
+_git_reset ()
+{
+ local cur="${COMP_WORDS[COMP_CWORD]}"
+ local opt="--mixed --hard --soft"
+ COMPREPLY=($(compgen -W "$opt $(__git_refs)" -- "$cur"))
+}
+
_git_show ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
- COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
+ COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
}
_git ()
{
- if [ $COMP_CWORD = 1 ]; then
+ local i c=1 command __git_dir
+
+ while [ $c -lt $COMP_CWORD ]; do
+ i="${COMP_WORDS[c]}"
+ case "$i" in
+ --git-dir=*) __git_dir="${i#--git-dir=}" ;;
+ --bare) __git_dir="." ;;
+ --version|--help|-p|--paginate) ;;
+ *) command="$i"; break ;;
+ esac
+ c=$((++c))
+ done
+
+ if [ $c -eq $COMP_CWORD -a -z "$command" ]; then
COMPREPLY=($(compgen \
- -W "--version $(git help -a|egrep '^ ') \
+ -W "--git-dir= --version \
+ $(git help -a|egrep '^ ') \
$(__git_aliases)" \
-- "${COMP_WORDS[COMP_CWORD]}"))
- else
- local command="${COMP_WORDS[1]}"
- local expansion=$(__git_aliased_command "$command")
+ return;
+ fi
- if [ "$expansion" ]; then
- command="$expansion"
- fi
+ local expansion=$(__git_aliased_command "$command")
+ [ "$expansion" ] && command="$expansion"
- case "$command" in
- branch) _git_branch ;;
- cat-file) _git_cat_file ;;
- checkout) _git_checkout ;;
- diff) _git_diff ;;
- diff-tree) _git_diff_tree ;;
- fetch) _git_fetch ;;
- log) _git_log ;;
- ls-remote) _git_ls_remote ;;
- ls-tree) _git_ls_tree ;;
- pull) _git_pull ;;
- push) _git_push ;;
- show) _git_show ;;
- show-branch) _git_log ;;
- whatchanged) _git_log ;;
- *) COMPREPLY=() ;;
- esac
- fi
+ case "$command" in
+ branch) _git_branch ;;
+ cat-file) _git_cat_file ;;
+ checkout) _git_checkout ;;
+ diff) _git_diff ;;
+ diff-tree) _git_diff_tree ;;
+ fetch) _git_fetch ;;
+ log) _git_log ;;
+ ls-remote) _git_ls_remote ;;
+ ls-tree) _git_ls_tree ;;
+ merge-base) _git_merge_base ;;
+ pull) _git_pull ;;
+ push) _git_push ;;
+ reset) _git_reset ;;
+ show) _git_show ;;
+ show-branch) _git_log ;;
+ whatchanged) _git_log ;;
+ *) COMPREPLY=() ;;
+ esac
}
_gitk ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
- COMPREPLY=($(compgen -W "--all $(__git_refs .)" -- "$cur"))
+ COMPREPLY=($(compgen -W "--all $(__git_refs)" -- "$cur"))
}
complete -o default -o nospace -F _git git
complete -o default -F _git_merge_base git-merge-base
complete -o default -o nospace -F _git_pull git-pull
complete -o default -o nospace -F _git_push git-push
+complete -o default -F _git_reset git-reset
complete -o default -F _git_show git-show
+complete -o default -o nospace -F _git_log git-show-branch
complete -o default -o nospace -F _git_log git-whatchanged
# The following are necessary only for Cygwin, and only are needed
# when the user has tab-completed the executable name and consequently
# included the '.exe' suffix.
#
+if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
+complete -o default -o nospace -F _git git.exe
+complete -o default -F _git_branch git-branch.exe
complete -o default -o nospace -F _git_cat_file git-cat-file.exe
complete -o default -o nospace -F _git_diff git-diff.exe
complete -o default -o nospace -F _git_diff_tree git-diff-tree.exe
complete -o default -o nospace -F _git_ls_tree git-ls-tree.exe
complete -o default -F _git_merge_base git-merge-base.exe
complete -o default -o nospace -F _git_push git-push.exe
+complete -o default -o nospace -F _git_log git-show-branch.exe
complete -o default -o nospace -F _git_log git-whatchanged.exe
+fi
(let ((commit (git-commit-tree buffer tree head)))
(git-update-ref "HEAD" commit head)
(condition-case nil (delete-file ".git/MERGE_HEAD") (error nil))
+ (condition-case nil (delete-file ".git/MERGE_MSG") (error nil))
(with-current-buffer buffer (erase-buffer))
(git-set-files-state files 'uptodate)
(when (file-directory-p ".git/rr-cache")
(unless git-status (error "Not in git-status buffer."))
(ewoc-goto-prev git-status n))
+(defun git-next-unmerged-file (&optional n)
+ "Move the selection down N unmerged files."
+ (interactive "p")
+ (unless git-status (error "Not in git-status buffer."))
+ (let* ((last (ewoc-locate git-status))
+ (node (ewoc-next git-status last)))
+ (while (and node (> n 0))
+ (when (eq 'unmerged (git-fileinfo->state (ewoc-data node)))
+ (setq n (1- n))
+ (setq last node))
+ (setq node (ewoc-next git-status node)))
+ (ewoc-goto-node git-status last)))
+
+(defun git-prev-unmerged-file (&optional n)
+ "Move the selection up N unmerged files."
+ (interactive "p")
+ (unless git-status (error "Not in git-status buffer."))
+ (let* ((last (ewoc-locate git-status))
+ (node (ewoc-prev git-status last)))
+ (while (and node (> n 0))
+ (when (eq 'unmerged (git-fileinfo->state (ewoc-data node)))
+ (setq n (1- n))
+ (setq last node))
+ (setq node (ewoc-prev git-status node)))
+ (ewoc-goto-node git-status last)))
+
(defun git-add-file ()
"Add marked file(s) to the index cache."
(interactive)
'face 'git-header-face)
(propertize git-log-msg-separator 'face 'git-separator-face)
"\n")
- (cond ((and merge-heads (file-readable-p ".git/MERGE_MSG"))
+ (cond ((file-readable-p ".git/MERGE_MSG")
(insert-file-contents ".git/MERGE_MSG"))
(sign-off
(insert (format "\n\nSigned-off-by: %s <%s>\n"
(2 font-lock-function-name-face))
(,(concat "^\\(" (regexp-quote git-log-msg-separator) "\\)$")
(1 font-lock-comment-face)))))
- (log-edit #'git-do-commit nil #'git-log-edit-files buffer))))
+ (log-edit #'git-do-commit nil #'git-log-edit-files buffer)
+ (re-search-forward (regexp-quote (concat git-log-msg-separator "\n")) nil t))))
(defun git-find-file ()
"Visit the current file in its own buffer."
(when (eq 'unmerged (git-fileinfo->state info))
(smerge-mode))))
+(defun git-find-file-other-window ()
+ "Visit the current file in its own buffer in another window."
+ (interactive)
+ (unless git-status (error "Not in git-status buffer."))
+ (let ((info (ewoc-data (ewoc-locate git-status))))
+ (find-file-other-window (git-fileinfo->name info))
+ (when (eq 'unmerged (git-fileinfo->state info))
+ (smerge-mode))))
+
(defun git-find-file-imerge ()
"Visit the current file in interactive merge mode."
(interactive)
(define-key map "m" 'git-mark-file)
(define-key map "M" 'git-mark-all)
(define-key map "n" 'git-next-file)
+ (define-key map "N" 'git-next-unmerged-file)
+ (define-key map "o" 'git-find-file-other-window)
(define-key map "p" 'git-prev-file)
+ (define-key map "P" 'git-prev-unmerged-file)
(define-key map "q" 'git-status-quit)
(define-key map "r" 'git-remove-file)
(define-key map "R" 'git-resolve-file)
+++ /dev/null
-#!/bin/sh
-#
-# Copyright (c) 2005 Junio C Hamano.
-#
-
-USAGE='[-v] <upstream> [<head>] [<limit>]'
-LONG_USAGE=' __*__*__*__*__> <upstream>
- /
- fork-point
- \__+__+__+__+__+__+__+__> <head>
-
-Each commit between the fork-point (or <limit> if given) and <head> is
-examined, and compared against the change each commit between the
-fork-point and <upstream> introduces. If the change seems to be in
-the upstream, it is shown on the standard output with prefix "-".
-Otherwise it is shown with prefix "+".'
-. git-sh-setup
-
-case "$1" in -v) verbose=t; shift ;; esac
-
-case "$#,$1" in
-1,*..*)
- upstream=$(expr "z$1" : 'z\(.*\)\.\.') ours=$(expr "z$1" : '.*\.\.\(.*\)$')
- set x "$upstream" "$ours"
- shift ;;
-esac
-
-case "$#" in
-1) upstream=`git-rev-parse --verify "$1"` &&
- ours=`git-rev-parse --verify HEAD` || exit
- limit="$upstream"
- ;;
-2) upstream=`git-rev-parse --verify "$1"` &&
- ours=`git-rev-parse --verify "$2"` || exit
- limit="$upstream"
- ;;
-3) upstream=`git-rev-parse --verify "$1"` &&
- ours=`git-rev-parse --verify "$2"` &&
- limit=`git-rev-parse --verify "$3"` || exit
- ;;
-*) usage ;;
-esac
-
-# Note that these list commits in reverse order;
-# not that the order in inup matters...
-inup=`git-rev-list ^$ours $upstream` &&
-ours=`git-rev-list $ours ^$limit` || exit
-
-tmp=.cherry-tmp$$
-patch=$tmp-patch
-mkdir $patch
-trap "rm -rf $tmp-*" 0 1 2 3 15
-
-for c in $inup
-do
- git-diff-tree -p $c
-done | git-patch-id |
-while read id name
-do
- echo $name >>$patch/$id
-done
-
-LF='
-'
-
-O=
-for c in $ours
-do
- set x `git-diff-tree -p $c | git-patch-id`
- if test "$2" != ""
- then
- if test -f "$patch/$2"
- then
- sign=-
- else
- sign=+
- fi
- case "$verbose" in
- t)
- c=$(git-rev-list --pretty=oneline --max-count=1 $c)
- esac
- case "$O" in
- '') O="$sign $c" ;;
- *) O="$sign $c$LF$O" ;;
- esac
- fi
-done
-case "$O" in
-'') ;;
-*) echo "$O" ;;
-esac
}
sub libsvn_get_file {
- my ($gui, $f, $rev) = @_;
+ my ($gui, $f, $rev, $chg) = @_;
my $p = $f;
if (length $SVN_PATH > 0) {
return unless ($p =~ s#^\Q$SVN_PATH\E/##);
}
+ print "\t$chg\t$f\n" unless $_q;
my ($hash, $pid, $in, $out);
my $pool = SVN::Pool->new;
$pool->clear;
}
foreach (@amr) {
- print "\t$_->[0]\t$_->[1]\n" unless $_q;
- libsvn_get_file($gui, $_->[1], $rev)
+ libsvn_get_file($gui, $_->[1], $rev, $_->[0]);
}
close $gui or croak $?;
return libsvn_log_entry($rev, $author, $date, $msg, [$last_commit]);
if (defined $files) {
push @$files, $file;
} else {
- print "\tA\t$file\n" unless $_q;
- libsvn_get_file($gui, $file, $rev);
+ libsvn_get_file($gui, $file, $rev, 'A');
}
}
}
my $ref = "refs/remotes/$GIT_SVN";
if (safe_qx('git-ls-remote', $origin, $ref)) {
sys(qw/git fetch/, $origin, "$ref:$ref");
- } else {
+ } elsif ($_cp_remote && !$_upgrade) {
die "Unable to find remote reference: ",
"refs/remotes/$GIT_SVN on $origin\n";
}
'pathinfo' => {
'override' => 0,
'default' => [0]},
+
+ # Make gitweb consider projects in project root subdirectories
+ # to be forks of existing projects. Given project $projname.git,
+ # projects matching $projname/*.git will not be shown in the main
+ # projects list, instead a '+' mark will be added to $projname
+ # there and a 'forks' view will be enabled for the project, listing
+ # all the forks. This feature is supported only if project list
+ # is taken from a directory, not file.
+
+ # To enable system wide have in $GITWEB_CONFIG
+ # $feature{'forks'}{'default'} = [1];
+ # Project specific override is not supported.
+ 'forks' => {
+ 'override' => 0,
+ 'default' => [0]},
);
sub gitweb_check_feature {
"commitdiff" => \&git_commitdiff,
"commitdiff_plain" => \&git_commitdiff_plain,
"commit" => \&git_commit,
+ "forks" => \&git_forks,
"heads" => \&git_heads,
"history" => \&git_history,
"log" => \&git_log,
}
sub git_get_projects_list {
+ my ($filter) = @_;
my @list;
+ $filter ||= '';
+ $filter =~ s/\.git$//;
+
if (-d $projects_list) {
# search in directory
- my $dir = $projects_list;
+ my $dir = $projects_list . ($filter ? "/$filter" : '');
+ # remove the trailing "/"
+ $dir =~ s!/+$!!;
my $pfxlen = length("$dir");
+ my $check_forks = gitweb_check_feature('forks');
+
File::Find::find({
follow_fast => 1, # follow symbolic links
dangling_symlinks => 0, # ignore dangling symlinks, silently
my $subdir = substr($File::Find::name, $pfxlen + 1);
# we check related file in $projectroot
- if (check_export_ok("$projectroot/$subdir")) {
- push @list, { path => $subdir };
+ if ($check_forks and $subdir =~ m#/.#) {
+ $File::Find::prune = 1;
+ } elsif (check_export_ok("$projectroot/$filter/$subdir")) {
+ push @list, { path => ($filter ? "$filter/" : '') . $subdir };
$File::Find::prune = 1;
}
},
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+sub git_project_list_body {
+ my ($projlist, $order, $from, $to, $extra, $no_header) = @_;
+
+ my $check_forks = gitweb_check_feature('forks');
+
+ my @projects;
+ foreach my $pr (@$projlist) {
+ my (@aa) = git_get_last_activity($pr->{'path'});
+ unless (@aa) {
+ next;
+ }
+ ($pr->{'age'}, $pr->{'age_string'}) = @aa;
+ if (!defined $pr->{'descr'}) {
+ my $descr = git_get_project_description($pr->{'path'}) || "";
+ $pr->{'descr'} = chop_str($descr, 25, 5);
+ }
+ if (!defined $pr->{'owner'}) {
+ $pr->{'owner'} = get_file_owner("$projectroot/$pr->{'path'}") || "";
+ }
+ if ($check_forks) {
+ my $pname = $pr->{'path'};
+ $pname =~ s/\.git$//;
+ $pr->{'forks'} = -d "$projectroot/$pname";
+ }
+ push @projects, $pr;
+ }
+
+ $order ||= "project";
+ $from = 0 unless defined $from;
+ $to = $#projects if (!defined $to || $#projects < $to);
+
+ print "<table class=\"project_list\">\n";
+ unless ($no_header) {
+ print "<tr>\n";
+ if ($check_forks) {
+ print "<th></th>\n";
+ }
+ if ($order eq "project") {
+ @projects = sort {$a->{'path'} cmp $b->{'path'}} @projects;
+ print "<th>Project</th>\n";
+ } else {
+ print "<th>" .
+ $cgi->a({-href => href(project=>undef, order=>'project'),
+ -class => "header"}, "Project") .
+ "</th>\n";
+ }
+ if ($order eq "descr") {
+ @projects = sort {$a->{'descr'} cmp $b->{'descr'}} @projects;
+ print "<th>Description</th>\n";
+ } else {
+ print "<th>" .
+ $cgi->a({-href => href(project=>undef, order=>'descr'),
+ -class => "header"}, "Description") .
+ "</th>\n";
+ }
+ if ($order eq "owner") {
+ @projects = sort {$a->{'owner'} cmp $b->{'owner'}} @projects;
+ print "<th>Owner</th>\n";
+ } else {
+ print "<th>" .
+ $cgi->a({-href => href(project=>undef, order=>'owner'),
+ -class => "header"}, "Owner") .
+ "</th>\n";
+ }
+ if ($order eq "age") {
+ @projects = sort {$a->{'age'} <=> $b->{'age'}} @projects;
+ print "<th>Last Change</th>\n";
+ } else {
+ print "<th>" .
+ $cgi->a({-href => href(project=>undef, order=>'age'),
+ -class => "header"}, "Last Change") .
+ "</th>\n";
+ }
+ print "<th></th>\n" .
+ "</tr>\n";
+ }
+ my $alternate = 1;
+ for (my $i = $from; $i <= $to; $i++) {
+ my $pr = $projects[$i];
+ if ($alternate) {
+ print "<tr class=\"dark\">\n";
+ } else {
+ print "<tr class=\"light\">\n";
+ }
+ $alternate ^= 1;
+ if ($check_forks) {
+ print "<td>";
+ if ($pr->{'forks'}) {
+ print $cgi->a({-href => href(project=>$pr->{'path'}, action=>"forks")}, "+");
+ }
+ print "</td>\n";
+ }
+ print "<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
+ -class => "list"}, esc_html($pr->{'path'})) . "</td>\n" .
+ "<td>" . esc_html($pr->{'descr'}) . "</td>\n" .
+ "<td><i>" . chop_str($pr->{'owner'}, 15) . "</i></td>\n";
+ print "<td class=\"". age_class($pr->{'age'}) . "\">" .
+ $pr->{'age_string'} . "</td>\n" .
+ "<td class=\"link\">" .
+ $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary")}, "summary") . " | " .
+ $cgi->a({-href => '/git-browser/by-commit.html?r='.$pr->{'path'}}, "graphiclog") . " | " .
+ $cgi->a({-href => href(project=>$pr->{'path'}, action=>"log")}, "log") . " | " .
+ $cgi->a({-href => href(project=>$pr->{'path'}, action=>"tree")}, "tree") .
+ ($pr->{'forks'} ? " | " . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"forks")}, "forks") : '') .
+ "</td>\n" .
+ "</tr>\n";
+ }
+ if (defined $extra) {
+ print "<tr>\n";
+ if ($check_forks) {
+ print "<td></td>\n";
+ }
+ print "<td colspan=\"5\">$extra</td>\n" .
+ "</tr>\n";
+ }
+ print "</table>\n";
+}
+
sub git_shortlog_body {
# uses global variable $project
my ($revlist, $from, $to, $refs, $extra) = @_;
}
my @list = git_get_projects_list();
- my @projects;
if (!@list) {
die_error(undef, "No projects found");
}
- foreach my $pr (@list) {
- my (@aa) = git_get_last_activity($pr->{'path'});
- unless (@aa) {
- next;
- }
- ($pr->{'age'}, $pr->{'age_string'}) = @aa;
- if (!defined $pr->{'descr'}) {
- my $descr = git_get_project_description($pr->{'path'}) || "";
- $pr->{'descr'} = chop_str($descr, 25, 5);
- }
- if (!defined $pr->{'owner'}) {
- $pr->{'owner'} = get_file_owner("$projectroot/$pr->{'path'}") || "";
- }
- push @projects, $pr;
- }
git_header_html();
if (-f $home_text) {
close $fd;
print "</div>\n";
}
- print "<table class=\"project_list\">\n" .
- "<tr>\n";
- $order ||= "project";
- if ($order eq "project") {
- @projects = sort {$a->{'path'} cmp $b->{'path'}} @projects;
- print "<th>Project</th>\n";
- } else {
- print "<th>" .
- $cgi->a({-href => href(project=>undef, order=>'project'),
- -class => "header"}, "Project") .
- "</th>\n";
- }
- if ($order eq "descr") {
- @projects = sort {$a->{'descr'} cmp $b->{'descr'}} @projects;
- print "<th>Description</th>\n";
- } else {
- print "<th>" .
- $cgi->a({-href => href(project=>undef, order=>'descr'),
- -class => "header"}, "Description") .
- "</th>\n";
- }
- if ($order eq "owner") {
- @projects = sort {$a->{'owner'} cmp $b->{'owner'}} @projects;
- print "<th>Owner</th>\n";
- } else {
- print "<th>" .
- $cgi->a({-href => href(project=>undef, order=>'owner'),
- -class => "header"}, "Owner") .
- "</th>\n";
- }
- if ($order eq "age") {
- @projects = sort {$a->{'age'} <=> $b->{'age'}} @projects;
- print "<th>Last Change</th>\n";
- } else {
- print "<th>" .
- $cgi->a({-href => href(project=>undef, order=>'age'),
- -class => "header"}, "Last Change") .
- "</th>\n";
+ git_project_list_body(\@list, $order);
+ git_footer_html();
+}
+
+sub git_forks {
+ my $order = $cgi->param('o');
+ if (defined $order && $order !~ m/project|descr|owner|age/) {
+ die_error(undef, "Unknown order parameter");
}
- print "<th></th>\n" .
- "</tr>\n";
- my $alternate = 1;
- foreach my $pr (@projects) {
- if ($alternate) {
- print "<tr class=\"dark\">\n";
- } else {
- print "<tr class=\"light\">\n";
- }
- $alternate ^= 1;
- print "<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
- -class => "list"}, esc_html($pr->{'path'})) . "</td>\n" .
- "<td>" . esc_html($pr->{'descr'}) . "</td>\n" .
- "<td><i>" . chop_str($pr->{'owner'}, 15) . "</i></td>\n";
- print "<td class=\"". age_class($pr->{'age'}) . "\">" .
- $pr->{'age_string'} . "</td>\n" .
- "<td class=\"link\">" .
- $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary")}, "summary") . " | " .
- $cgi->a({-href => href(project=>$pr->{'path'}, action=>"shortlog")}, "shortlog") . " | " .
- $cgi->a({-href => href(project=>$pr->{'path'}, action=>"log")}, "log") . " | " .
- $cgi->a({-href => href(project=>$pr->{'path'}, action=>"tree")}, "tree") .
- "</td>\n" .
- "</tr>\n";
+
+ my @list = git_get_projects_list($project);
+ if (!@list) {
+ die_error(undef, "No forks found");
}
- print "</table>\n";
+
+ git_header_html();
+ git_print_page_nav('','');
+ git_print_header_div('summary', "$project forks");
+ git_project_list_body(\@list, $order);
git_footer_html();
}
sub git_project_index {
- my @projects = git_get_projects_list();
+ my @projects = git_get_projects_list($project);
print $cgi->header(
-type => 'text/plain',
my $refs = git_get_references();
my @taglist = git_get_tags_list(15);
my @headlist = git_get_heads_list(15);
+ my @forklist;
+ if (gitweb_check_feature('forks')) {
+ @forklist = git_get_projects_list($project);
+ }
git_header_html();
git_print_page_nav('summary','', $head);
$cgi->a({-href => href(action=>"heads")}, "..."));
}
+ if (@forklist) {
+ git_print_header_div('forks');
+ git_project_list_body(\@forklist, undef, 0, 15,
+ $cgi->a({-href => href(action=>"forks")}, "..."),
+ 'noheader');
+ }
+
git_footer_html();
}
const char *branch1, *branch2;
struct commit *result, *h1, *h2;
+ git_config(git_default_config); /* core.filemode */
original_index_file = getenv("GIT_INDEX_FILE");
if (!original_index_file)
: 0));
if (S_ISDIR(mode))
mode |= S_ISGID;
- if (chmod(path, mode) < 0)
+ if ((mode & st.st_mode) != mode && chmod(path, mode) < 0)
return -2;
return 0;
}
{
static const char *args[] = {
"pack-objects",
+ "--all-progress",
"--stdout",
NULL
};
static void wt_status_print_updated(struct wt_status *s)
{
struct rev_info rev;
- const char *argv[] = { NULL, NULL, NULL };
- argv[1] = s->reference;
init_revisions(&rev, NULL);
- setup_revisions(2, argv, &rev, NULL);
+ setup_revisions(0, NULL, &rev, s->reference);
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
rev.diffopt.format_callback = wt_status_print_updated_cb;
rev.diffopt.format_callback_data = s;
static void wt_status_print_changed(struct wt_status *s)
{
struct rev_info rev;
- const char *argv[] = { NULL, NULL };
init_revisions(&rev, "");
- setup_revisions(1, argv, &rev, NULL);
+ setup_revisions(0, NULL, &rev, NULL);
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
rev.diffopt.format_callback = wt_status_print_changed_cb;
rev.diffopt.format_callback_data = s;
static void wt_status_print_verbose(struct wt_status *s)
{
struct rev_info rev;
- const char *argv[] = { NULL, NULL, NULL };
- argv[1] = s->reference;
init_revisions(&rev, NULL);
- setup_revisions(2, argv, &rev, NULL);
+ setup_revisions(0, NULL, &rev, s->reference);
rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
rev.diffopt.detect_rename = 1;
run_diff_index(&rev, 1);