summaryrefslogtreecommitdiff
path: root/contrib/examples
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/examples')
-rw-r--r--contrib/examples/builtin-fetch--tool.c574
-rwxr-xr-xcontrib/examples/git-commit.sh2
-rwxr-xr-xcontrib/examples/git-fetch.sh4
-rwxr-xr-xcontrib/examples/git-merge.sh126
-rwxr-xr-xcontrib/examples/git-notes.sh121
-rwxr-xr-xcontrib/examples/git-resolve.sh2
-rwxr-xr-xcontrib/examples/git-revert.sh14
-rwxr-xr-xcontrib/examples/git-svnimport.perl4
8 files changed, 810 insertions, 37 deletions
diff --git a/contrib/examples/builtin-fetch--tool.c b/contrib/examples/builtin-fetch--tool.c
new file mode 100644
index 0000000000..0d54aa7061
--- /dev/null
+++ b/contrib/examples/builtin-fetch--tool.c
@@ -0,0 +1,574 @@
+#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, 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, 1)) {
+ 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, &not_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-commit.sh b/contrib/examples/git-commit.sh
index 5c72f655c7..23ffb028d1 100755
--- a/contrib/examples/git-commit.sh
+++ b/contrib/examples/git-commit.sh
@@ -631,7 +631,7 @@ then
if test -z "$quiet"
then
commit=`git diff-tree --always --shortstat --pretty="format:%h: %s"\
- --summary --root HEAD --`
+ --abbrev --summary --root HEAD --`
echo "Created${initial_commit:+ initial} commit $commit"
fi
fi
diff --git a/contrib/examples/git-fetch.sh b/contrib/examples/git-fetch.sh
index e44af2c86d..a314273bd5 100755
--- a/contrib/examples/git-fetch.sh
+++ b/contrib/examples/git-fetch.sh
@@ -127,10 +127,12 @@ then
orig_head=$(git rev-parse --verify HEAD 2>/dev/null)
fi
-# Allow --notags from remote.$1.tagopt
+# Allow --tags/--notags from remote.$1.tagopt
case "$tags$no_tags" in
'')
case "$(git config --get "remote.$1.tagopt")" in
+ --tags)
+ tags=t ;;
--no-tags)
no_tags=t ;;
esac
diff --git a/contrib/examples/git-merge.sh b/contrib/examples/git-merge.sh
index e9588eec33..7b922c3948 100755
--- a/contrib/examples/git-merge.sh
+++ b/contrib/examples/git-merge.sh
@@ -14,8 +14,11 @@ 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 allow fast-forward (default)
+ff-only abort if fast-forward is not possible
+rerere-autoupdate update index with any reused conflict resolution
s,strategy= merge strategy to use
+X= option for selected merge strategy
m,message= message to be used for the merge commit (if any)
"
@@ -25,25 +28,32 @@ require_work_tree
cd_to_toplevel
test -z "$(git ls-files -u)" ||
- die "You are in the middle of a conflicted merge."
+ die "Merge is not possible because you have unmerged files."
+
+! test -e "$GIT_DIR/MERGE_HEAD" ||
+ die 'You have not concluded your merge (MERGE_HEAD exists).'
LF='
'
all_strategies='recur recursive octopus resolve stupid ours subtree'
+all_strategies="$all_strategies recursive-ours recursive-theirs"
+not_strategies='base file index tree'
default_twohead_strategies='recursive'
default_octopus_strategies='octopus'
no_fast_forward_strategies='subtree ours'
-no_trivial_strategies='recursive recur subtree ours'
+no_trivial_strategies='recursive recur subtree ours recursive-ours recursive-theirs'
use_strategies=
+xopt=
allow_fast_forward=t
+fast_forward_only=
allow_trivial_merge=t
-squash= no_commit= log_arg=
+squash= no_commit= log_arg= rr_arg=
dropsave() {
rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" \
- "$GIT_DIR/MERGE_STASH" || exit 1
+ "$GIT_DIR/MERGE_STASH" "$GIT_DIR/MERGE_MODE" || exit 1
}
savestate() {
@@ -130,21 +140,34 @@ finish () {
merge_name () {
remote="$1"
rh=$(git rev-parse --verify "$remote^0" 2>/dev/null) || return
- bh=$(git show-ref -s --verify "refs/heads/$remote" 2>/dev/null)
- if test "$rh" = "$bh"
- then
- echo "$rh branch '$remote' of ."
- elif truname=$(expr "$remote" : '\(.*\)~[1-9][0-9]*$') &&
+ if truname=$(expr "$remote" : '\(.*\)~[0-9]*$') &&
git show-ref -q --verify "refs/heads/$truname" 2>/dev/null
then
echo "$rh branch '$truname' (early part) of ."
- elif test "$remote" = "FETCH_HEAD" -a -r "$GIT_DIR/FETCH_HEAD"
+ return
+ fi
+ if found_ref=$(git rev-parse --symbolic-full-name --verify \
+ "$remote" 2>/dev/null)
+ then
+ expanded=$(git check-ref-format --branch "$remote") ||
+ exit
+ if test "${found_ref#refs/heads/}" != "$found_ref"
+ then
+ echo "$rh branch '$expanded' of ."
+ return
+ elif test "${found_ref#refs/remotes/}" != "$found_ref"
+ then
+ echo "$rh remote branch '$expanded' of ."
+ return
+ fi
+ fi
+ if test "$remote" = "FETCH_HEAD" -a -r "$GIT_DIR/FETCH_HEAD"
then
sed -e 's/ not-for-merge / /' -e 1q \
"$GIT_DIR/FETCH_HEAD"
- else
- echo "$rh commit '$remote'"
+ return
fi
+ echo "$rh commit '$remote'"
}
parse_config () {
@@ -171,16 +194,36 @@ parse_config () {
--no-ff)
test "$squash" != t ||
die "You cannot combine --squash with --no-ff."
+ test "$fast_forward_only" != t ||
+ die "You cannot combine --ff-only with --no-ff."
allow_fast_forward=f ;;
+ --ff-only)
+ test "$allow_fast_forward" != f ||
+ die "You cannot combine --ff-only with --no-ff."
+ fast_forward_only=t ;;
+ --rerere-autoupdate|--no-rerere-autoupdate)
+ rr_arg=$1 ;;
-s|--strategy)
shift
case " $all_strategies " in
*" $1 "*)
- use_strategies="$use_strategies$1 " ;;
+ use_strategies="$use_strategies$1 "
+ ;;
*)
- die "available strategies are: $all_strategies" ;;
+ case " $not_strategies " in
+ *" $1 "*)
+ false
+ esac &&
+ type "git-merge-$1" >/dev/null 2>&1 ||
+ die "available strategies are: $all_strategies"
+ use_strategies="$use_strategies$1 "
+ ;;
esac
;;
+ -X)
+ shift
+ xopt="${xopt:+$xopt }$(git rev-parse --sq-quote "--$1")"
+ ;;
-m|--message)
shift
merge_msg="$1"
@@ -244,6 +287,10 @@ then
exit 1
fi
+ test "$squash" != t ||
+ die "Squash commit into empty head not supported yet"
+ test "$allow_fast_forward" = t ||
+ die "Non-fast-forward into an empty head does not make sense"
rh=$(git rev-parse --verify "$1^0") ||
die "$1 - not something we can merge"
@@ -260,12 +307,18 @@ else
# the given message. If remote is invalid we will die
# later in the common codepath so we discard the error
# in this loop.
- merge_name=$(for remote
+ merge_msg="$(
+ for remote
do
merge_name "$remote"
- done | git fmt-merge-msg $log_arg
- )
- merge_msg="${merge_msg:+$merge_msg$LF$LF}$merge_name"
+ done |
+ if test "$have_message" = t
+ then
+ git fmt-merge-msg -m "$merge_msg" $log_arg
+ else
+ git fmt-merge-msg $log_arg
+ fi
+ )"
fi
head=$(git rev-parse --verify "$head_arg"^0) || usage
@@ -334,7 +387,7 @@ case "$#" in
common=$(git merge-base --all $head "$@")
;;
*)
- common=$(git show-branch --merge-base $head "$@")
+ common=$(git merge-base --all --octopus $head "$@")
;;
esac
echo "$head" >"$GIT_DIR/ORIG_HEAD"
@@ -353,7 +406,7 @@ 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"
+ msg="Fast-forward"
if test -n "$have_message"
then
msg="$msg (no commit created; -m option ignored)"
@@ -365,15 +418,15 @@ t,1,"$head",*)
exit 0
;;
?,1,?*"$LF"?*,*)
- # We are not doing octopus and not fast forward. Need a
+ # 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
+ # We are not doing octopus, not fast-forward, and have only
# one common.
git update-index --refresh 2>/dev/null
- case "$allow_trivial_merge" in
- t)
+ case "$allow_trivial_merge,$fast_forward_only" in
+ t,)
# See if it is really trivial.
git var GIT_COMMITTER_IDENT >/dev/null || exit
echo "Trying really trivial in-index merge..."
@@ -412,6 +465,11 @@ t,1,"$head",*)
;;
esac
+if test "$fast_forward_only" = t
+then
+ die "Not possible to fast-forward, aborting."
+fi
+
# We are going to make a new commit.
git var GIT_COMMITTER_IDENT >/dev/null || exit
@@ -450,7 +508,7 @@ do
# Remember which strategy left the state in the working tree
wt_strategy=$strategy
- git-merge-$strategy $common -- "$head_arg" "$@"
+ eval 'git-merge-$strategy '"$xopt"' $common -- "$head_arg" "$@"'
exit=$?
if test "$no_commit" = t && test "$exit" = 0
then
@@ -488,9 +546,9 @@ if test '' != "$result_tree"
then
if test "$allow_fast_forward" = "t"
then
- parents=$(git show-branch --independent "$head" "$@")
+ parents=$(git merge-base --independent "$head" "$@")
else
- parents=$(git rev-parse "$head" "$@")
+ parents=$(git rev-parse "$head" "$@")
fi
parents=$(echo "$parents" | sed -e 's/^/-p /')
result_commit=$(printf '%s\n' "$merge_msg" | git commit-tree $result_tree $parents) || exit
@@ -532,7 +590,15 @@ else
do
echo $remote
done >"$GIT_DIR/MERGE_HEAD"
- printf '%s\n' "$merge_msg" >"$GIT_DIR/MERGE_MSG"
+ printf '%s\n' "$merge_msg" >"$GIT_DIR/MERGE_MSG" ||
+ die "Could not write to $GIT_DIR/MERGE_MSG"
+ if test "$allow_fast_forward" != t
+ then
+ printf "%s" no-ff
+ else
+ :
+ fi >"$GIT_DIR/MERGE_MODE" ||
+ die "Could not write to $GIT_DIR/MERGE_MODE"
fi
if test "$merge_was_ok" = t
@@ -549,6 +615,6 @@ Conflicts:
sed -e 's/^[^ ]* / /' |
uniq
} >>"$GIT_DIR/MERGE_MSG"
- git rerere
+ git rerere $rr_arg
die "Automatic merge failed; fix conflicts and then commit the result."
fi
diff --git a/contrib/examples/git-notes.sh b/contrib/examples/git-notes.sh
new file mode 100755
index 0000000000..e642e47d9f
--- /dev/null
+++ b/contrib/examples/git-notes.sh
@@ -0,0 +1,121 @@
+#!/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-resolve.sh b/contrib/examples/git-resolve.sh
index 0ee1bd898e..8f98142f77 100755
--- a/contrib/examples/git-resolve.sh
+++ b/contrib/examples/git-resolve.sh
@@ -48,7 +48,7 @@ case "$common" in
"$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" \
+ git update-ref -m "resolve $merge_name: Fast-forward" \
HEAD "$merge" "$head"
git diff-tree -p $head $merge | git apply --stat
dropheads
diff --git a/contrib/examples/git-revert.sh b/contrib/examples/git-revert.sh
index 49f00321b2..6bf155cbdb 100755
--- a/contrib/examples/git-revert.sh
+++ b/contrib/examples/git-revert.sh
@@ -26,6 +26,7 @@ require_work_tree
cd_to_toplevel
no_commit=
+xopt=
while case "$#" in 0) break ;; esac
do
case "$1" in
@@ -44,6 +45,16 @@ do
-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
;;
@@ -159,7 +170,7 @@ export GITHEAD_$head GITHEAD_$next
# and $prev on top of us (when reverting), or the change between
# $prev and $commit on top of us (when cherry-picking or replaying).
-git-merge-recursive $base -- $head $next &&
+eval "git merge-recursive $xopt $base -- $head $next" &&
result=$(git-write-tree 2>/dev/null) || {
mv -f .msg "$GIT_DIR/MERGE_MSG"
{
@@ -181,7 +192,6 @@ Conflicts:
esac
exit 1
}
-echo >&2 "Finished one $me."
# If we are cherry-pick, and if the merge did not result in
# hand-editing, we will hit this commit and inherit the original
diff --git a/contrib/examples/git-svnimport.perl b/contrib/examples/git-svnimport.perl
index 4576c4a862..b09ff8f12f 100755
--- a/contrib/examples/git-svnimport.perl
+++ b/contrib/examples/git-svnimport.perl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
# This tool is copyright (c) 2005, Matthias Urlichs.
# It is released under the Gnu Public License, version 2.
@@ -289,7 +289,7 @@ my $current_rev = $opt_s || 1;
unless(-d $git_dir) {
system("git init");
die "Cannot init the GIT db at $git_tree: $?\n" if $?;
- system("git read-tree");
+ system("git read-tree --empty");
die "Cannot init an empty tree: $?\n" if $?;
$last_branch = $opt_o;