summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rwxr-xr-xDocumentation/cmd-list.perl1
-rw-r--r--Documentation/config.txt5
-rw-r--r--Documentation/git-branch.txt9
-rw-r--r--Documentation/git-checkout.txt15
-rw-r--r--Documentation/git-cvsserver.txt19
-rw-r--r--Documentation/git-mergetool.txt46
-rw-r--r--Documentation/git-svn.txt8
-rw-r--r--Makefile2
-rw-r--r--builtin-add.c18
-rw-r--r--builtin-branch.c153
-rw-r--r--builtin-grep.c15
-rw-r--r--builtin-shortlog.c5
-rw-r--r--cache.h1
-rwxr-xr-xgit-checkout.sh17
-rwxr-xr-xgit-mergetool.sh352
-rwxr-xr-xgit-svn.perl7
-rw-r--r--perl/Makefile2
-rwxr-xr-xt/t3200-branch.sh65
-rw-r--r--trace.c18
20 files changed, 703 insertions, 56 deletions
diff --git a/.gitignore b/.gitignore
index 0eaba0a278..27797d1491 100644
--- a/.gitignore
+++ b/.gitignore
@@ -75,6 +75,7 @@ git-merge-ours
git-merge-recursive
git-merge-resolve
git-merge-stupid
+git-mergetool
git-mktag
git-mktree
git-name-rev
diff --git a/Documentation/cmd-list.perl b/Documentation/cmd-list.perl
index f61c77aa7c..b54382b2bf 100755
--- a/Documentation/cmd-list.perl
+++ b/Documentation/cmd-list.perl
@@ -124,6 +124,7 @@ git-merge-index plumbingmanipulators
git-merge mainporcelain
git-merge-one-file purehelpers
git-merge-tree ancillaryinterrogators
+git-mergetool ancillarymanipulators
git-mktag plumbingmanipulators
git-mktree plumbingmanipulators
git-mv mainporcelain
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5408dd67d3..aaae9ac305 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -453,6 +453,11 @@ merge.summary::
Whether to include summaries of merged commits in newly created
merge commit messages. False by default.
+merge.tool::
+ Controls which merge resolution program is used by
+ gitlink:git-mergetool[l]. Valid values are: "kdiff3", "tkdiff",
+ "meld", "xxdiff", "emerge"
+
merge.verbosity::
Controls the amount of output shown by the recursive merge
strategy. Level 0 outputs nothing except a final error
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 3ea3b80635..603f87f3b5 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -10,7 +10,7 @@ SYNOPSIS
[verse]
'git-branch' [--color | --no-color] [-r | -a]
[-v [--abbrev=<length> | --no-abbrev]]
-'git-branch' [-l] [-f] <branchname> [<start-point>]
+'git-branch' [--track | --no-track] [-l] [-f] <branchname> [<start-point>]
'git-branch' (-m | -M) [<oldbranch>] <newbranch>
'git-branch' (-d | -D) [-r] <branchname>...
@@ -26,6 +26,13 @@ It will start out with a head equal to the one given as <start-point>.
If no <start-point> is given, the branch will be created with a head
equal to that of the currently checked out branch.
+When a local branch is started off a remote branch, git can setup the
+branch so that gitlink:git-pull[1] will appropriately merge from that
+remote branch. If this behavior is desired, it is possible to make it
+the default using the global `branch.autosetupmerge` configuration
+flag. Otherwise, it can be chosen per-branch using the `--track`
+and `--no-track` options.
+
With a '-m' or '-M' option, <oldbranch> will be renamed to <newbranch>.
If <oldbranch> had a corresponding reflog, it is renamed to match
<newbranch>, and a reflog entry is created to remember the branch
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 1ae77be450..f5b2d5017b 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -8,7 +8,7 @@ git-checkout - Checkout and switch to a branch
SYNOPSIS
--------
[verse]
-'git-checkout' [-q] [-f] [-b <new_branch> [-l]] [-m] [<branch>]
+'git-checkout' [-q] [-f] [-b [--track | --no-track] <new_branch> [-l]] [-m] [<branch>]
'git-checkout' [<tree-ish>] <paths>...
DESCRIPTION
@@ -18,7 +18,8 @@ When <paths> are not given, this command switches branches by
updating the index and working tree to reflect the specified
branch, <branch>, and updating HEAD to be <branch> or, if
specified, <new_branch>. Using -b will cause <new_branch> to
-be created.
+be created; in this case you can use the --track or --no-track
+options, which will be passed to `git branch`.
When <paths> are given, this command does *not* switch
branches. It updates the named paths in the working tree from
@@ -45,6 +46,16 @@ OPTIONS
by gitlink:git-check-ref-format[1]. Some of these checks
may restrict the characters allowed in a branch name.
+--track::
+ When -b is given and a branch is created off a remote branch,
+ setup so that git-pull will automatically retrieve data from
+ the remote branch.
+
+--no-track::
+ When -b is given and a branch is created off a remote branch,
+ force that git-pull will automatically retrieve data from
+ the remote branch independent of the configuration settings.
+
-l::
Create the new branch's ref log. This activates recording of
all changes to made the branch ref, enabling use of date
diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt
index e328db3797..1c6f6a7e27 100644
--- a/Documentation/git-cvsserver.txt
+++ b/Documentation/git-cvsserver.txt
@@ -121,10 +121,10 @@ so that calling 'cvs' effectively calls git-cvsserver.
Clients known to work
---------------------
-CVS 1.12.9 on Debian
-CVS 1.11.17 on MacOSX (from Fink package)
-Eclipse 3.0, 3.1.2 on MacOSX (see Eclipse CVS Client Notes)
-TortoiseCVS
+- CVS 1.12.9 on Debian
+- CVS 1.11.17 on MacOSX (from Fink package)
+- Eclipse 3.0, 3.1.2 on MacOSX (see Eclipse CVS Client Notes)
+- TortoiseCVS
Operations supported
--------------------
@@ -148,13 +148,16 @@ Copyright and Authors
This program is copyright The Open University UK - 2006.
-Authors: Martyn Smith <martyn@catalyst.net.nz>
- Martin Langhoff <martin@catalyst.net.nz>
- with ideas and patches from participants of the git-list <git@vger.kernel.org>.
+Authors:
+
+- Martyn Smith <martyn@catalyst.net.nz>
+- Martin Langhoff <martin@catalyst.net.nz>
+
+with ideas and patches from participants of the git-list <git@vger.kernel.org>.
Documentation
--------------
-Documentation by Martyn Smith <martyn@catalyst.net.nz> and Martin Langhoff <martin@catalyst.net.nz> Matthias Urlichs <smurf@smurf.noris.de>.
+Documentation by Martyn Smith <martyn@catalyst.net.nz>, Martin Langhoff <martin@catalyst.net.nz>, and Matthias Urlichs <smurf@smurf.noris.de>.
GIT
---
diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt
new file mode 100644
index 0000000000..ae69a0eb83
--- /dev/null
+++ b/Documentation/git-mergetool.txt
@@ -0,0 +1,46 @@
+git-mergetool(1)
+================
+
+NAME
+----
+git-mergetool - Run merge conflict resolution tools to resolve merge conflicts
+
+SYNOPSIS
+--------
+'git-mergetool' [--tool=<tool>] [<file>]...
+
+DESCRIPTION
+-----------
+
+Use 'git mergetool' to run one of several merge utilities to resolve
+merge conflicts. It is typically run after gitlink:git-merge[1].
+
+If one or more <file> parameters are given, the merge tool program will
+be run to resolve differences on each file. If no <file> names are
+specified, 'git mergetool' will run the merge tool program on every file
+with merge conflicts.
+
+OPTIONS
+-------
+-t or --tool=<tool>::
+ Use the merge resolution program specified by <tool>.
+ Valid merge tools are:
+ kdiff3, tkdiff, meld, xxdiff, and emerge.
+
+ If a merge resolution program is not specified, 'git mergetool'
+ will use the configuration variable merge.tool. If the
+ configuration variable merge.tool is not set, 'git mergetool'
+ will pick a suitable default.
+
+Author
+------
+Written by Theodore Y Ts'o <tytso@mit.edu>
+
+Documentation
+--------------
+Documentation by Theodore Y Ts'o.
+
+GIT
+---
+Part of the gitlink:git[7] suite
+
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index 9b5a3d6196..a0d34e0058 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -104,6 +104,14 @@ accepts. However '--fetch-all' only fetches from the current
Like 'git-rebase'; this requires that the working tree be clean
and have no uncommitted changes.
++
+--
+-l;;
+--local;;
+ Do not fetch remotely; only run 'git-rebase' against the
+ last fetched commit from the upstream SVN.
+--
++
'dcommit'::
Commit each diff from a specified head directly to the SVN
diff --git a/Makefile b/Makefile
index 1a51f84f53..45fe3663a5 100644
--- a/Makefile
+++ b/Makefile
@@ -179,7 +179,7 @@ SCRIPT_SH = \
git-clean.sh git-clone.sh git-commit.sh \
git-fetch.sh git-gc.sh \
git-ls-remote.sh \
- git-merge-one-file.sh git-parse-remote.sh \
+ git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \
git-pull.sh git-rebase.sh \
git-repack.sh git-request-pull.sh git-reset.sh \
git-sh-setup.sh \
diff --git a/builtin-add.c b/builtin-add.c
index 87e16aa220..9fcf514dbc 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -12,6 +12,8 @@
static const char builtin_add_usage[] =
"git-add [-n] [-v] [-f] [--interactive | -i] [--] <filepattern>...";
+static const char *excludes_file;
+
static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)
{
char *seen;
@@ -67,6 +69,8 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec)
path = git_path("info/exclude");
if (!access(path, R_OK))
add_excludes_from_file(dir, path);
+ if (!access(excludes_file, R_OK))
+ add_excludes_from_file(dir, excludes_file);
/*
* Calculate common prefix for the pathspec, and
@@ -88,6 +92,18 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec)
prune_directory(dir, pathspec, baselen);
}
+static int git_add_config(const char *var, const char *value)
+{
+ if (!strcmp(var, "core.excludesfile")) {
+ if (!value)
+ die("core.excludesfile without value");
+ excludes_file = xstrdup(value);
+ return 0;
+ }
+
+ return git_default_config(var, value);
+}
+
static struct lock_file lock_file;
static const char ignore_warning[] =
@@ -115,7 +131,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
exit(1);
}
- git_config(git_default_config);
+ git_config(git_add_config);
newfd = hold_lock_file_for_update(&lock_file, get_index_file(), 1);
diff --git a/builtin-branch.c b/builtin-branch.c
index 06d8a8ce04..42b1ff129e 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -12,7 +12,7 @@
#include "builtin.h"
static const char builtin_branch_usage[] =
- "git-branch [-r] (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length> | --no-abbrev]]";
+ "git-branch [-r] (-d | -D) <branchname> | [--track | --no-track] [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length> | --no-abbrev]]";
#define REF_UNKNOWN_TYPE 0x00
#define REF_LOCAL_BRANCH 0x01
@@ -22,6 +22,8 @@ static const char builtin_branch_usage[] =
static const char *head;
static unsigned char head_sha1[20];
+static int branch_track_remotes;
+
static int branch_use_color;
static char branch_colors[][COLOR_MAXLEN] = {
"\033[m", /* reset */
@@ -64,6 +66,9 @@ int git_branch_config(const char *var, const char *value)
color_parse(value, var, branch_colors[slot]);
return 0;
}
+ if (!strcmp(var, "branch.autosetupmerge"))
+ branch_track_remotes = git_config_bool(var, value);
+
return git_default_config(var, value);
}
@@ -309,14 +314,108 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev)
free_ref_list(&ref_list);
}
+static char *config_repo;
+static char *config_remote;
+static const char *start_ref;
+static int start_len;
+static int base_len;
+
+static int get_remote_branch_name(const char *value)
+{
+ const char *colon;
+ const char *end;
+
+ if (*value == '+')
+ value++;
+
+ colon = strchr(value, ':');
+ if (!colon)
+ return 0;
+
+ end = value + strlen(value);
+
+ /* Try an exact match first. */
+ if (!strcmp(colon + 1, start_ref)) {
+ /* Truncate the value before the colon. */
+ nfasprintf(&config_repo, "%.*s", colon - value, value);
+ return 1;
+ }
+
+ /* Try with a wildcard match now. */
+ if (end - value > 2 && end[-2] == '/' && end[-1] == '*' &&
+ colon - value > 2 && colon[-2] == '/' && colon[-1] == '*' &&
+ (end - 2) - (colon + 1) == base_len &&
+ !strncmp(colon + 1, start_ref, base_len)) {
+ /* Replace the star with the remote branch name. */
+ nfasprintf(&config_repo, "%.*s%s",
+ (colon - 2) - value, value,
+ start_ref + base_len);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int get_remote_config(const char *key, const char *value)
+{
+ const char *var;
+ if (prefixcmp(key, "remote."))
+ return 0;
+
+ var = strrchr(key, '.');
+ if (var == key + 6)
+ return 0;
+
+ if (!strcmp(var, ".fetch") && get_remote_branch_name(value))
+ nfasprintf(&config_remote, "%.*s", var - (key + 7), key + 7);
+
+ return 0;
+}
+
+static void set_branch_defaults(const char *name, const char *real_ref)
+{
+ char key[1024];
+ const char *slash = strrchr(real_ref, '/');
+
+ if (!slash)
+ return;
+
+ start_ref = real_ref;
+ start_len = strlen(real_ref);
+ base_len = slash - real_ref;
+ git_config(get_remote_config);
+
+ if (config_repo && config_remote) {
+ if (sizeof(key) <=
+ snprintf(key, sizeof(key), "branch.%s.remote", name))
+ die("what a long branch name you have!");
+ git_config_set(key, config_remote);
+
+ /*
+ * We do not have to check if we have enough space for
+ * the 'merge' key, since it's shorter than the
+ * previous 'remote' key, which we already checked.
+ */
+ snprintf(key, sizeof(key), "branch.%s.merge", name);
+ git_config_set(key, config_repo);
+
+ printf("Branch %s set up to track remote branch %s.\n",
+ name, real_ref);
+ }
+
+ if (config_repo)
+ free(config_repo);
+ if (config_remote)
+ free(config_remote);
+}
+
static void create_branch(const char *name, const char *start_name,
- unsigned char *start_sha1,
- int force, int reflog)
+ int force, int reflog, int track)
{
struct ref_lock *lock;
struct commit *commit;
unsigned char sha1[20];
- char ref[PATH_MAX], msg[PATH_MAX + 20];
+ char *real_ref, ref[PATH_MAX], msg[PATH_MAX + 20];
int forcing = 0;
snprintf(ref, sizeof ref, "refs/heads/%s", name);
@@ -331,12 +430,23 @@ static void create_branch(const char *name, const char *start_name,
forcing = 1;
}
- if (start_sha1)
- /* detached HEAD */
- hashcpy(sha1, start_sha1);
- else if (get_sha1(start_name, sha1))
+ real_ref = NULL;
+ if (get_sha1(start_name, sha1))
die("Not a valid object name: '%s'.", start_name);
+ switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) {
+ case 0:
+ /* Not branching from any existing branch */
+ real_ref = NULL;
+ break;
+ case 1:
+ /* Unique completion -- good */
+ break;
+ default:
+ die("Ambiguous object name: '%s'.", start_name);
+ break;
+ }
+
if ((commit = lookup_commit_reference(sha1)) == NULL)
die("Not a valid branch point: '%s'.", start_name);
hashcpy(sha1, commit->object.sha1);
@@ -355,8 +465,17 @@ static void create_branch(const char *name, const char *start_name,
snprintf(msg, sizeof msg, "branch: Created from %s",
start_name);
+ /* When branching off a remote branch, set up so that git-pull
+ automatically merges from there. So far, this is only done for
+ remotes registered via .git/config. */
+ if (real_ref && track)
+ set_branch_defaults(name, real_ref);
+
if (write_ref_sha1(lock, sha1, msg) < 0)
die("Failed to write ref: %s.", strerror(errno));
+
+ if (real_ref)
+ free(real_ref);
}
static void rename_branch(const char *oldname, const char *newname, int force)
@@ -398,11 +517,12 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
int delete = 0, force_delete = 0, force_create = 0;
int rename = 0, force_rename = 0;
int verbose = 0, abbrev = DEFAULT_ABBREV, detached = 0;
- int reflog = 0;
+ int reflog = 0, track;
int kinds = REF_LOCAL_BRANCH;
int i;
git_config(git_branch_config);
+ track = branch_track_remotes;
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
@@ -413,6 +533,14 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
i++;
break;
}
+ if (!strcmp(arg, "--track")) {
+ track = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--no-track")) {
+ track = 0;
+ continue;
+ }
if (!strcmp(arg, "-d")) {
delete = 1;
continue;
@@ -498,10 +626,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
rename_branch(head, argv[i], force_rename);
else if (rename && (i == argc - 2))
rename_branch(argv[i], argv[i + 1], force_rename);
- else if (i == argc - 1)
- create_branch(argv[i], head, head_sha1, force_create, reflog);
- else if (i == argc - 2)
- create_branch(argv[i], argv[i+1], NULL, force_create, reflog);
+ else if (i == argc - 1 || i == argc - 2)
+ create_branch(argv[i], (i == argc - 2) ? argv[i+1] : head,
+ force_create, reflog, track);
else
usage(builtin_branch_usage);
diff --git a/builtin-grep.c b/builtin-grep.c
index 694da5ba09..4510d35324 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -431,6 +431,19 @@ static const char emsg_missing_context_len[] =
static const char emsg_missing_argument[] =
"option requires an argument -%s";
+static int strtoul_ui(char const *s, unsigned int *result)
+{
+ unsigned long ul;
+ char *p;
+
+ errno = 0;
+ ul = strtoul(s, &p, 10);
+ if (errno || *p || p == s || (unsigned int) ul != ul)
+ return -1;
+ *result = ul;
+ return 0;
+}
+
int cmd_grep(int argc, const char **argv, const char *prefix)
{
int hit = 0;
@@ -553,7 +566,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
scan = arg + 1;
break;
}
- if (sscanf(scan, "%u", &num) != 1)
+ if (strtoul_ui(scan, &num))
die(emsg_invalid_context_len, scan);
switch (arg[1]) {
case 'A':
diff --git a/builtin-shortlog.c b/builtin-shortlog.c
index 2d7726e8b9..29343aefc8 100644
--- a/builtin-shortlog.c
+++ b/builtin-shortlog.c
@@ -304,8 +304,11 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
if (!access(".mailmap", R_OK))
read_mailmap(".mailmap");
- if (rev.pending.nr == 0)
+ if (rev.pending.nr == 0) {
+ if (isatty(0))
+ fprintf(stderr, "(reading log to summarize from standard input)\n");
read_from_stdin(&list);
+ }
else
get_from_rev(&rev, &list);
diff --git a/cache.h b/cache.h
index f172d02a65..faed2a8994 100644
--- a/cache.h
+++ b/cache.h
@@ -480,6 +480,7 @@ extern struct tag *alloc_tag_node(void);
extern void alloc_report(void);
/* trace.c */
+extern int nfasprintf(char **str, const char *fmt, ...);
extern int nfvasprintf(char **str, const char *fmt, va_list va);
extern void trace_printf(const char *format, ...);
extern void trace_argv_printf(const char **argv, int count, const char *format, ...);
diff --git a/git-checkout.sh b/git-checkout.sh
index 14835a4aa9..6caa9fdcc6 100755
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -12,6 +12,7 @@ new=
new_name=
force=
branch=
+track=
newbranch=
newbranch_log=
merge=
@@ -33,7 +34,10 @@ while [ "$#" != "0" ]; do
die "git checkout: we do not like '$newbranch' as a branch name."
;;
"-l")
- newbranch_log=1
+ newbranch_log=-l
+ ;;
+ "--track"|"--no-track")
+ track="$arg"
;;
"-f")
force=1
@@ -85,6 +89,11 @@ while [ "$#" != "0" ]; do
esac
done
+case "$new_branch,$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"
@@ -235,11 +244,7 @@ fi
#
if [ "$?" -eq 0 ]; then
if [ "$newbranch" ]; then
- if [ "$newbranch_log" ]; then
- mkdir -p $(dirname "$GIT_DIR/logs/refs/heads/$newbranch")
- touch "$GIT_DIR/logs/refs/heads/$newbranch"
- fi
- git-update-ref -m "checkout: Created from $new_name" "refs/heads/$newbranch" $new || exit
+ git-branch $track $newbranch_log "$newbranch" "$new_name" || exit
branch="$newbranch"
fi
if test -n "$branch"
diff --git a/git-mergetool.sh b/git-mergetool.sh
new file mode 100755
index 0000000000..52386a5443
--- /dev/null
+++ b/git-mergetool.sh
@@ -0,0 +1,352 @@
+#!/bin/sh
+#
+# This program resolves merge conflicts in git
+#
+# Copyright (c) 2006 Theodore Y. Ts'o
+#
+# This file is licensed under the GPL v2, or a later version
+# at the discretion of Junio C Hammano.
+#
+
+USAGE='[--tool=tool] [file to merge] ...'
+SUBDIRECTORY_OK=Yes
+. git-sh-setup
+require_work_tree
+
+# Returns true if the mode reflects a symlink
+function is_symlink () {
+ test "$1" = 120000
+}
+
+function local_present () {
+ test -n "$local_mode"
+}
+
+function remote_present () {
+ test -n "$remote_mode"
+}
+
+function base_present () {
+ test -n "$base_mode"
+}
+
+cleanup_temp_files () {
+ if test "$1" = --save-backup ; then
+ mv -- "$BACKUP" "$path.orig"
+ rm -f -- "$LOCAL" "$REMOTE" "$BASE"
+ else
+ rm -f -- "$LOCAL" "$REMOTE" "$BASE" "$BACKUP"
+ fi
+}
+
+function describe_file () {
+ mode="$1"
+ branch="$2"
+ file="$3"
+
+ echo -n " "
+ if test -z "$mode"; then
+ echo -n "'$path' was deleted"
+ elif is_symlink "$mode" ; then
+ echo -n "'$path' is a symlink containing '"
+ cat "$file"
+ echo -n "'"
+ else
+ if base_present; then
+ echo -n "'$path' was created"
+ else
+ echo -n "'$path' was modified"
+ fi
+ fi
+ echo " in the $branch branch"
+}
+
+
+resolve_symlink_merge () {
+ while /bin/true; do
+ echo -n "Use (r)emote or (l)ocal, or (a)bort? "
+ read ans
+ case "$ans" in
+ [lL]*)
+ git-checkout-index -f --stage=2 -- "$path"
+ git-add -- "$path"
+ cleanup_temp_files --save-backup
+ return
+ ;;
+ [rR]*)
+ git-checkout-index -f --stage=3 -- "$path"
+ git-add -- "$path"
+ cleanup_temp_files --save-backup
+ return
+ ;;
+ [qQ]*)
+ exit 1
+ ;;
+ esac
+ done
+}
+
+resolve_deleted_merge () {
+ while /bin/true; do
+ echo -n "Use (m)odified or (d)eleted file, or (a)bort? "
+ read ans
+ case "$ans" in
+ [mM]*)
+ git-add -- "$path"
+ cleanup_temp_files --save-backup
+ return
+ ;;
+ [dD]*)
+ git-rm -- "$path"
+ cleanup_temp_files
+ return
+ ;;
+ [qQ]*)
+ exit 1
+ ;;
+ esac
+ done
+}
+
+merge_file () {
+ path="$1"
+
+ if test ! -f "$path" ; then
+ echo "$path: file not found"
+ exit 1
+ fi
+
+ f=`git-ls-files -u -- "$path"`
+ if test -z "$f" ; then
+ echo "$path: file does not need merging"
+ exit 1
+ fi
+
+ BACKUP="$path.BACKUP.$$"
+ LOCAL="$path.LOCAL.$$"
+ REMOTE="$path.REMOTE.$$"
+ BASE="$path.BASE.$$"
+
+ mv -- "$path" "$BACKUP"
+ cp -- "$BACKUP" "$path"
+
+ base_mode=`git ls-files -u -- "$path" | awk '{if ($3==1) print $1;}'`
+ local_mode=`git ls-files -u -- "$path" | awk '{if ($3==2) print $1;}'`
+ remote_mode=`git ls-files -u -- "$path" | awk '{if ($3==3) print $1;}'`
+
+ base_present && git cat-file blob ":1:$path" > "$BASE" 2>/dev/null
+ local_present && git cat-file blob ":2:$path" > "$LOCAL" 2>/dev/null
+ remote_present && git cat-file blob ":3:$path" > "$REMOTE" 2>/dev/null
+
+ if test -z "$local_mode" -o -z "$remote_mode"; then
+ echo "Deleted merge conflict for $path:"
+ describe_file "$local_mode" "local" "$LOCAL"
+ describe_file "$remote_mode" "remote" "$REMOTE"
+ resolve_deleted_merge
+ return
+ fi
+
+ if is_symlink "$local_mode" || is_symlink "$remote_mode"; then
+ echo "Symlink merge conflict for $path:"
+ describe_file "$local_mode" "local" "$LOCAL"
+ describe_file "$remote_mode" "remote" "$REMOTE"
+ resolve_symlink_merge
+ return
+ fi
+
+ echo "Normal merge conflict for $path:"
+ describe_file "$local_mode" "local" "$LOCAL"
+ describe_file "$remote_mode" "remote" "$REMOTE"
+ echo -n "Hit return to start merge resolution tool ($merge_tool): "
+ read ans
+
+ case "$merge_tool" in
+ kdiff3)
+ if base_present ; then
+ (kdiff3 --auto --L1 "$path (Base)" -L2 "$path (Local)" --L3 "$path (Remote)" \
+ -o "$path" -- "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1)
+ else
+ (kdiff3 --auto -L1 "$path (Local)" --L2 "$path (Remote)" \
+ -o "$path" -- "$LOCAL" "$REMOTE" > /dev/null 2>&1)
+ fi
+ status=$?
+ if test "$status" -eq 0; then
+ rm "$BACKUP"
+ fi
+ ;;
+ tkdiff)
+ if base_present ; then
+ tkdiff -a "$BASE" -o "$path" -- "$LOCAL" "$REMOTE"
+ else
+ tkdiff -o "$path" -- "$LOCAL" "$REMOTE"
+ fi
+ status=$?
+ if test "$status" -eq 0; then
+ mv -- "$BACKUP" "$path.orig"
+ fi
+ ;;
+ meld)
+ touch "$BACKUP"
+ meld -- "$LOCAL" "$path" "$REMOTE"
+ if test "$path" -nt "$BACKUP" ; then
+ status=0;
+ else
+ while true; do
+ echo "$path seems unchanged."
+ echo -n "Was the merge successful? [y/n] "
+ read answer < /dev/tty
+ case "$answer" in
+ y*|Y*) status=0; break ;;
+ n*|N*) status=1; break ;;
+ esac
+ done
+ fi
+ if test "$status" -eq 0; then
+ mv -- "$BACKUP" "$path.orig"
+ fi
+ ;;
+ xxdiff)
+ touch "$BACKUP"
+ if base_present ; then
+ xxdiff -X --show-merged-pane \
+ -R 'Accel.SaveAsMerged: "Ctrl-S"' \
+ -R 'Accel.Search: "Ctrl+F"' \
+ -R 'Accel.SearchForward: "Ctrl-G"' \
+ --merged-file "$path" -- "$LOCAL" "$BASE" "$REMOTE"
+ else
+ xxdiff -X --show-merged-pane \
+ -R 'Accel.SaveAsMerged: "Ctrl-S"' \
+ -R 'Accel.Search: "Ctrl+F"' \
+ -R 'Accel.SearchForward: "Ctrl-G"' \
+ --merged-file "$path" -- "$LOCAL" "$REMOTE"
+ fi
+ if test "$path" -nt "$BACKUP" ; then
+ status=0;
+ else
+ while true; do
+ echo "$path seems unchanged."
+ echo -n "Was the merge successful? [y/n] "
+ read answer < /dev/tty
+ case "$answer" in
+ y*|Y*) status=0; break ;;
+ n*|N*) status=1; break ;;
+ esac
+ done
+ fi
+ if test "$status" -eq 0; then
+ mv -- "$BACKUP" "$path.orig"
+ fi
+ ;;
+ emerge)
+ if base_present ; then
+ emacs -f emerge-files-with-ancestor-command "$LOCAL" "$REMOTE" "$BASE" "$path"
+ else
+ emacs -f emerge-files-command "$LOCAL" "$REMOTE" "$path"
+ fi
+ status=$?
+ if test "$status" -eq 0; then
+ mv -- "$BACKUP" "$path.orig"
+ fi
+ ;;
+ esac
+ if test "$status" -ne 0; then
+ echo "merge of $path failed" 1>&2
+ mv -- "$BACKUP" "$path"
+ exit 1
+ fi
+ git add -- "$path"
+ cleanup_temp_files
+}
+
+while case $# in 0) break ;; esac
+do
+ case "$1" in
+ -t|--tool*)
+ case "$#,$1" in
+ *,*=*)
+ merge_tool=`expr "z$1" : 'z-[^=]*=\(.*\)'`
+ ;;
+ 1,*)
+ usage ;;
+ *)
+ merge_tool="$2"
+ shift ;;
+ esac
+ ;;
+ --)
+ break
+ ;;
+ -*)
+ usage
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+done
+
+if test -z "$merge_tool"; then
+ merge_tool=`git-config merge.tool`
+ if test $merge_tool = kdiff3 -o $merge_tool = tkdiff -o \
+ $merge_tool = xxdiff -o $merge_tool = meld ; then
+ unset merge_tool
+ fi
+fi
+
+if test -z "$merge_tool" ; then
+ if type kdiff3 >/dev/null 2>&1 && test -n "$DISPLAY"; then
+ merge_tool="kdiff3";
+ elif type tkdiff >/dev/null 2>&1 && test -n "$DISPLAY"; then
+ merge_tool=tkdiff
+ elif type xxdiff >/dev/null 2>&1 && test -n "$DISPLAY"; then
+ merge_tool=xxdiff
+ elif type meld >/dev/null 2>&1 && test -n "$DISPLAY"; then
+ merge_tool=meld
+ elif type emacs >/dev/null 2>&1; then
+ merge_tool=emerge
+ else
+ echo "No available merge resolution programs available."
+ exit 1
+ fi
+fi
+
+case "$merge_tool" in
+ kdiff3|tkdiff|meld|xxdiff)
+ if ! type "$merge_tool" > /dev/null 2>&1; then
+ echo "The merge tool $merge_tool is not available"
+ exit 1
+ fi
+ ;;
+ emerge)
+ if ! type "emacs" > /dev/null 2>&1; then
+ echo "Emacs is not available"
+ exit 1
+ fi
+ ;;
+ *)
+ echo "Unknown merge tool: $merge_tool"
+ exit 1
+ ;;
+esac
+
+if test $# -eq 0 ; then
+ files=`git ls-files -u | sed -e 's/^[^ ]* //' | sort -u`
+ if test -z "$files" ; then
+ echo "No files need merging"
+ exit 0
+ fi
+ echo Merging the files: $files
+ git ls-files -u | sed -e 's/^[^ ]* //' | sort -u | while read i
+ do
+ echo ""
+ merge_file "$i" < /dev/tty > /dev/tty
+ done
+else
+ while test $# -gt 0; do
+ echo ""
+ merge_file "$1"
+ shift
+ done
+fi
+exit 0
diff --git a/git-svn.perl b/git-svn.perl
index 326e89fe03..e8457893db 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -56,7 +56,7 @@ my ($_stdin, $_help, $_edit,
$_message, $_file,
$_template, $_shared,
$_version, $_fetch_all,
- $_merge, $_strategy, $_dry_run,
+ $_merge, $_strategy, $_dry_run, $_local,
$_prefix, $_no_checkout, $_verbose);
$Git::SVN::_follow_parent = 1;
my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
@@ -145,6 +145,7 @@ my %cmd = (
{ 'merge|m|M' => \$_merge,
'verbose|v' => \$_verbose,
'strategy|s=s' => \$_strategy,
+ 'local|l' => \$_local,
'fetch-all|all' => \$_fetch_all,
%fc_opts } ],
'commit-diff' => [ \&cmd_commit_diff,
@@ -439,7 +440,9 @@ sub cmd_rebase {
command_noisy('status');
exit 1;
}
- $_fetch_all ? $gs->fetch_all : $gs->fetch;
+ unless ($_local) {
+ $_fetch_all ? $gs->fetch_all : $gs->fetch;
+ }
command_noisy(rebase_cmd(), $gs->refname);
}
diff --git a/perl/Makefile b/perl/Makefile
index 5ec0389883..17d004e5a0 100644
--- a/perl/Makefile
+++ b/perl/Makefile
@@ -33,7 +33,7 @@ $(makfile): ../GIT-CFLAGS Makefile
echo ' echo $(instdir_SQ)' >> $@
else
$(makfile): Makefile.PL ../GIT-CFLAGS
- $(QUIET_GEN)'$(PERL_PATH_SQ)' $< PREFIX='$(prefix_SQ)'
+ '$(PERL_PATH_SQ)' $< PREFIX='$(prefix_SQ)'
endif
# this is just added comfort for calling make directly in perl dir
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 5565c27033..75c000a968 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -47,17 +47,6 @@ test_expect_success \
test ! -f .git/refs/heads/d/e/f &&
test ! -f .git/logs/refs/heads/d/e/f'
-cat >expect <<EOF
-0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 checkout: Created from master
-EOF
-test_expect_success \
- 'git checkout -b g/h/i -l should create a branch and a log' \
- 'GIT_COMMITTER_DATE="2005-05-26 23:30" \
- git-checkout -b g/h/i -l master &&
- test -f .git/refs/heads/g/h/i &&
- test -f .git/logs/refs/heads/g/h/i &&
- diff expect .git/logs/refs/heads/g/h/i'
-
test_expect_success \
'git branch j/k should work after branch j has been deleted' \
'git-branch j &&
@@ -117,4 +106,58 @@ test_expect_failure \
ln -s real-u .git/logs/refs/heads/u &&
git-branch -m u v'
+test_expect_success 'test tracking setup via --track' \
+ 'git-config remote.local.url . &&
+ git-config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+ (git-show-ref -q refs/remotes/local/master || git-fetch local) &&
+ git-branch --track my1 local/master &&
+ test $(git-config branch.my1.remote) = local &&
+ test $(git-config branch.my1.merge) = refs/heads/master'
+
+test_expect_success 'test tracking setup (non-wildcard, matching)' \
+ 'git-config remote.local.url . &&
+ git-config remote.local.fetch refs/heads/master:refs/remotes/local/master &&
+ (git-show-ref -q refs/remotes/local/master || git-fetch local) &&
+ git-branch --track my4 local/master &&
+ test $(git-config branch.my4.remote) = local &&
+ test $(git-config branch.my4.merge) = refs/heads/master'
+
+test_expect_success 'test tracking setup (non-wildcard, not matching)' \
+ 'git-config remote.local.url . &&
+ git-config remote.local.fetch refs/heads/s:refs/remotes/local/s &&
+ (git-show-ref -q refs/remotes/local/master || git-fetch local) &&
+ git-branch --track my5 local/master &&
+ ! test $(git-config branch.my5.remote) = local &&
+ ! test $(git-config branch.my5.merge) = refs/heads/master'
+
+test_expect_success 'test tracking setup via config' \
+ 'git-config branch.autosetupmerge true &&
+ git-config remote.local.url . &&
+ git-config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+ (git-show-ref -q refs/remotes/local/master || git-fetch local) &&
+ git-branch my3 local/master &&
+ test $(git-config branch.my3.remote) = local &&
+ test $(git-config branch.my3.merge) = refs/heads/master'
+
+test_expect_success 'test overriding tracking setup via --no-track' \
+ 'git-config branch.autosetupmerge true &&
+ git-config remote.local.url . &&
+ git-config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+ (git-show-ref -q refs/remotes/local/master || git-fetch local) &&
+ git-branch --no-track my2 local/master &&
+ ! test $(git-config branch.my2.remote) = local &&
+ ! test $(git-config branch.my2.merge) = refs/heads/master'
+
+# Keep this test last, as it changes the current branch
+cat >expect <<EOF
+0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master
+EOF
+test_expect_success \
+ 'git checkout -b g/h/i -l should create a branch and a log' \
+ 'GIT_COMMITTER_DATE="2005-05-26 23:30" \
+ git-checkout -b g/h/i -l master &&
+ test -f .git/refs/heads/g/h/i &&
+ test -f .git/logs/refs/heads/g/h/i &&
+ diff expect .git/logs/refs/heads/g/h/i'
+
test_done
diff --git a/trace.c b/trace.c
index 27fef868c4..7961a27a2e 100644
--- a/trace.c
+++ b/trace.c
@@ -26,14 +26,14 @@
#include "quote.h"
/* Stolen from "imap-send.c". */
-static int git_vasprintf(char **strp, const char *fmt, va_list ap)
+int nfvasprintf(char **strp, const char *fmt, va_list ap)
{
int len;
char tmp[1024];
if ((len = vsnprintf(tmp, sizeof(tmp), fmt, ap)) < 0 ||
!(*strp = xmalloc(len + 1)))
- return -1;
+ die("Fatal: Out of memory\n");
if (len >= (int)sizeof(tmp))
vsprintf(*strp, fmt, ap);
else
@@ -41,13 +41,15 @@ static int git_vasprintf(char **strp, const char *fmt, va_list ap)
return len;
}
-/* Stolen from "imap-send.c". */
-int nfvasprintf(char **str, const char *fmt, va_list va)
+int nfasprintf(char **str, const char *fmt, ...)
{
- int ret = git_vasprintf(str, fmt, va);
- if (ret < 0)
- die("Fatal: Out of memory\n");
- return ret;
+ int rc;
+ va_list args;
+
+ va_start(args, fmt);
+ rc = nfvasprintf(str, fmt, args);
+ va_end(args);
+ return rc;
}
/* Get a trace file descriptor from GIT_TRACE env variable. */