* [PATCH 1/7] add new command git equal-tree-marker
2009-11-30 14:43 equal-tree-merges as way to make rebases fast-forward-able Bernhard R. Link
@ 2009-11-30 14:43 ` Bernhard R. Link
2009-11-30 15:36 ` Michael J Gruber
2009-11-30 14:44 ` [PATCH 2/7] add option to only visit the first parent of a equal tree merge Bernhard R. Link
` (12 subsequent siblings)
13 siblings, 1 reply; 29+ messages in thread
From: Bernhard R. Link @ 2009-11-30 14:43 UTC (permalink / raw)
To: git
This adds a new commit denoting tha current branch has the same
tree as another branch, thus allowing fast-forward from the named
commits to this one.
TODO: manpage, rewrite as builtin once the semantics are accepted?
---
.gitignore | 1 +
Makefile | 1 +
git-equal-tree-marker.sh | 50 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 52 insertions(+), 0 deletions(-)
create mode 100644 git-equal-tree-marker.sh
diff --git a/.gitignore b/.gitignore
index ac02a58..248d146 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,6 +39,7 @@
/git-difftool
/git-difftool--helper
/git-describe
+/git-equal-tree-marker
/git-fast-export
/git-fast-import
/git-fetch
diff --git a/Makefile b/Makefile
index 4dba10e..913d4c4 100644
--- a/Makefile
+++ b/Makefile
@@ -336,6 +336,7 @@ TEST_PROGRAMS =
SCRIPT_SH += git-am.sh
SCRIPT_SH += git-bisect.sh
SCRIPT_SH += git-difftool--helper.sh
+SCRIPT_SH += git-equal-tree-marker.sh
SCRIPT_SH += git-filter-branch.sh
SCRIPT_SH += git-lost-found.sh
SCRIPT_SH += git-merge-octopus.sh
diff --git a/git-equal-tree-marker.sh b/git-equal-tree-marker.sh
new file mode 100644
index 0000000..403cc56
--- /dev/null
+++ b/git-equal-tree-marker.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Bernhard R. Link
+#
+# Create a new commit making HEAD parent of the arguments,
+# which must be commits with the same tree.
+
+set -e
+
+USAGE='<head>...'
+LONG_USAGE='Make current HEAD parent of the given heads (which need to have the same tree).'
+SUBDIRECTORY_OK=Yes
+OPTIONS_SPEC=
+. git-sh-setup
+cd_to_toplevel
+
+# is there really no function for this?
+tree_of_commit() {
+ git cat-file commit "$1" | grep '^tree ' | head -n 1 | sed -e 's/^tree //'
+}
+
+head="$(git rev-parse --verify HEAD)"
+htree="$(tree_of_commit $head)"
+parents=""
+while test $# -gt 0
+do
+ case "$1" in
+ -h|--h|--he|--hel|--help)
+ usage
+ ;;
+ *)
+ h="$(git rev-parse --verify $1)"
+ tree="$(tree_of_commit "$h")"
+ if test "x${htree}" != "x${tree}" ; then
+ echo "Tree of $h is not the same as tree of $head" >&2
+ exit 1
+ fi
+ parents="$parents -p $h"
+ ;;
+ esac
+ shift
+done
+
+if test "x$parents" = "x" ; then
+ echo "Not enough arguments!" >&2
+ exit 1
+fi
+
+new_commit="$(echo "Equal tree marker" | git commit-tree "$tree" -p "$head" $parents)"
+git-update-ref HEAD "$new_commit"
--
1.6.6.rc0.82.g60a15.dirty
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] add new command git equal-tree-marker
2009-11-30 14:43 ` [PATCH 1/7] add new command git equal-tree-marker Bernhard R. Link
@ 2009-11-30 15:36 ` Michael J Gruber
0 siblings, 0 replies; 29+ messages in thread
From: Michael J Gruber @ 2009-11-30 15:36 UTC (permalink / raw)
To: Bernhard R. Link; +Cc: git
Bernhard R. Link venit, vidit, dixit 30.11.2009 15:43:
> This adds a new commit denoting tha current branch has the same
> tree as another branch, thus allowing fast-forward from the named
> commits to this one.
>
> TODO: manpage, rewrite as builtin once the semantics are accepted?
> ---
> .gitignore | 1 +
> Makefile | 1 +
> git-equal-tree-marker.sh | 50 ++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 52 insertions(+), 0 deletions(-)
> create mode 100644 git-equal-tree-marker.sh
>
> diff --git a/.gitignore b/.gitignore
> index ac02a58..248d146 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -39,6 +39,7 @@
> /git-difftool
> /git-difftool--helper
> /git-describe
> +/git-equal-tree-marker
> /git-fast-export
> /git-fast-import
> /git-fetch
> diff --git a/Makefile b/Makefile
> index 4dba10e..913d4c4 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -336,6 +336,7 @@ TEST_PROGRAMS =
> SCRIPT_SH += git-am.sh
> SCRIPT_SH += git-bisect.sh
> SCRIPT_SH += git-difftool--helper.sh
> +SCRIPT_SH += git-equal-tree-marker.sh
> SCRIPT_SH += git-filter-branch.sh
> SCRIPT_SH += git-lost-found.sh
> SCRIPT_SH += git-merge-octopus.sh
> diff --git a/git-equal-tree-marker.sh b/git-equal-tree-marker.sh
> new file mode 100644
> index 0000000..403cc56
> --- /dev/null
> +++ b/git-equal-tree-marker.sh
> @@ -0,0 +1,50 @@
> +#!/bin/sh
> +#
> +# Copyright (c) 2009 Bernhard R. Link
> +#
> +# Create a new commit making HEAD parent of the arguments,
> +# which must be commits with the same tree.
> +
> +set -e
> +
> +USAGE='<head>...'
> +LONG_USAGE='Make current HEAD parent of the given heads (which need to have the same tree).'
> +SUBDIRECTORY_OK=Yes
> +OPTIONS_SPEC=
> +. git-sh-setup
> +cd_to_toplevel
> +
> +# is there really no function for this?
> +tree_of_commit() {
> + git cat-file commit "$1" | grep '^tree ' | head -n 1 | sed -e 's/^tree //'
> +}
You mean there should be something really simple, such as:
git rev-parse "$1"^{tree}
Michael
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 2/7] add option to only visit the first parent of a equal tree merge
2009-11-30 14:43 equal-tree-merges as way to make rebases fast-forward-able Bernhard R. Link
2009-11-30 14:43 ` [PATCH 1/7] add new command git equal-tree-marker Bernhard R. Link
@ 2009-11-30 14:44 ` Bernhard R. Link
2009-11-30 14:44 ` [PATCH 3/7] format-patch defaults to --first-equal-tree-only Bernhard R. Link
` (11 subsequent siblings)
13 siblings, 0 replies; 29+ messages in thread
From: Bernhard R. Link @ 2009-11-30 14:44 UTC (permalink / raw)
To: git
rev_info gets a new flag first_equal_tree_only that causes
revision walks to ignore all but the first parent of equal tree
merges.
The default is off and there are options --first-equal-tree-only
and --all-equal-trees to switch it on/off respectively.
TODO:
- manpage updates
- check interaction with some of the other options
---
revision.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++---------
revision.h | 1 +
2 files changed, 49 insertions(+), 9 deletions(-)
diff --git a/revision.c b/revision.c
index a8a3c3a..fb019d6 100644
--- a/revision.c
+++ b/revision.c
@@ -452,6 +452,7 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
struct commit_list *parent = commit->parents;
unsigned left_flag;
struct commit_list *cached_base = cache_ptr ? *cache_ptr : NULL;
+ int first_parent_only;
if (commit->object.flags & ADDED)
return 0;
@@ -499,6 +500,21 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
left_flag = (commit->object.flags & SYMMETRIC_LEFT);
+ if (revs->first_parent_only)
+ first_parent_only = 1;
+ else if (revs->first_equal_tree_only && commit->parents) {
+ for (parent = commit->parents; parent; parent = parent->next) {
+ struct commit *p = parent->item;
+
+ if (parse_commit(p) < 0)
+ return -1;
+ if (p->tree != commit->tree)
+ break;
+ }
+ first_parent_only = !parent;
+ } else
+ first_parent_only = 0;
+
for (parent = commit->parents; parent; parent = parent->next) {
struct commit *p = parent->item;
@@ -511,7 +527,7 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
p->object.flags |= SEEN;
insert_by_date_cached(p, list, cached_base, cache_ptr);
}
- if (revs->first_parent_only)
+ if (first_parent_only)
break;
}
return 0;
@@ -1067,6 +1083,10 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->min_age = approxidate(arg + 8);
} else if (!strcmp(arg, "--first-parent")) {
revs->first_parent_only = 1;
+ } else if (!strcmp(arg, "--first-equal-tree-only")) {
+ revs->first_equal_tree_only = 1;
+ } else if (!strcmp(arg, "--all-equal-trees")) {
+ revs->first_equal_tree_only = 0;
} else if (!strcmp(arg, "-g") || !strcmp(arg, "--walk-reflogs")) {
init_reflog_walk(&revs->reflog_info);
} else if (!strcmp(arg, "--default")) {
@@ -1912,6 +1932,16 @@ static void create_boundary_commit_list(struct rev_info *revs)
sort_in_topological_order(&revs->commits, revs->lifo);
}
+static inline void add_boundary_commit(struct rev_info *revs, struct commit *c) {
+ struct object *p = &c->object;
+
+ if (p->flags & (CHILD_SHOWN | SHOWN))
+ return;
+ p->flags |= CHILD_SHOWN;
+ gc_boundary(&revs->boundary_commits);
+ add_object_array(p, NULL, &revs->boundary_commits);
+}
+
static struct commit *get_revision_internal(struct rev_info *revs)
{
struct commit *c = NULL;
@@ -1987,16 +2017,25 @@ static struct commit *get_revision_internal(struct rev_info *revs)
* 'c', we need to mark its parents that they could be boundaries.
*/
- for (l = c->parents; l; l = l->next) {
- struct object *p;
- p = &(l->item->object);
- if (p->flags & (CHILD_SHOWN | SHOWN))
- continue;
- p->flags |= CHILD_SHOWN;
- gc_boundary(&revs->boundary_commits);
- add_object_array(p, NULL, &revs->boundary_commits);
+ if (revs->first_equal_tree_only && c->parents) {
+ for (l = c->parents; l; l = l->next) {
+ struct commit *p = l->item;
+ parse_commit(p);
+ if (c->tree != p->tree)
+ break;
+ }
+ /* if all parents have the same tree as this node,
+ * it's an equal tree merge, so ignore all but the
+ * first parent */
+ if (!l) {
+ add_boundary_commit(revs, c->parents->item);
+ return c;
+ }
}
+ for (l = c->parents; l; l = l->next) {
+ add_boundary_commit(revs, l->item);
+ }
return c;
}
diff --git a/revision.h b/revision.h
index d368003..7ac263c 100644
--- a/revision.h
+++ b/revision.h
@@ -64,6 +64,7 @@ struct rev_info {
reverse_output_stage:1,
cherry_pick:1,
bisect:1,
+ first_equal_tree_only:1,
first_parent_only:1;
/* Diff flags */
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 3/7] format-patch defaults to --first-equal-tree-only
2009-11-30 14:43 equal-tree-merges as way to make rebases fast-forward-able Bernhard R. Link
2009-11-30 14:43 ` [PATCH 1/7] add new command git equal-tree-marker Bernhard R. Link
2009-11-30 14:44 ` [PATCH 2/7] add option to only visit the first parent of a equal tree merge Bernhard R. Link
@ 2009-11-30 14:44 ` Bernhard R. Link
2009-11-30 14:44 ` [PATCH 4/7] support equal tree merges in interactive rebase Bernhard R. Link
` (10 subsequent siblings)
13 siblings, 0 replies; 29+ messages in thread
From: Bernhard R. Link @ 2009-11-30 14:44 UTC (permalink / raw)
To: git
TODO: manpage update to hint to --all-equal-trees?
---
builtin-log.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/builtin-log.c b/builtin-log.c
index 33fa6ea..a3a2d3f 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -960,6 +960,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.diff = 1;
rev.combine_merges = 0;
rev.ignore_merges = 1;
+ rev.first_equal_tree_only = 1;
DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
rev.subject_prefix = fmt_patch_subject_prefix;
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 4/7] support equal tree merges in interactive rebase
2009-11-30 14:43 equal-tree-merges as way to make rebases fast-forward-able Bernhard R. Link
` (2 preceding siblings ...)
2009-11-30 14:44 ` [PATCH 3/7] format-patch defaults to --first-equal-tree-only Bernhard R. Link
@ 2009-11-30 14:44 ` Bernhard R. Link
2009-11-30 14:45 ` [PATCH 5/7] make rebase -m equal tree marker aware Bernhard R. Link
` (9 subsequent siblings)
13 siblings, 0 replies; 29+ messages in thread
From: Bernhard R. Link @ 2009-11-30 14:44 UTC (permalink / raw)
To: git
---
git-rebase--interactive.sh | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 0bd3bf7..3da9f3e 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -703,6 +703,7 @@ first and then run 'git rebase --continue' again."
fi
git rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \
--abbrev=7 --reverse --left-right --topo-order \
+ --first-equal-tree-only \
$REVISIONS | \
sed -n "s/^>//p" | while read shortsha1 rest
do
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 5/7] make rebase -m equal tree marker aware
2009-11-30 14:43 equal-tree-merges as way to make rebases fast-forward-able Bernhard R. Link
` (3 preceding siblings ...)
2009-11-30 14:44 ` [PATCH 4/7] support equal tree merges in interactive rebase Bernhard R. Link
@ 2009-11-30 14:45 ` Bernhard R. Link
2009-11-30 14:45 ` [PATCH 6/7] add support for creating equal tree markers after rebase Bernhard R. Link
` (8 subsequent siblings)
13 siblings, 0 replies; 29+ messages in thread
From: Bernhard R. Link @ 2009-11-30 14:45 UTC (permalink / raw)
To: git
---
git-rebase.sh | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/git-rebase.sh b/git-rebase.sh
index b121f45..391f6d6 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -539,7 +539,7 @@ echo "$head_name" > "$dotest/head-name"
echo "$GIT_QUIET" > "$dotest/quiet"
msgnum=0
-for cmt in `git rev-list --reverse --no-merges "$revisions"`
+for cmt in `git rev-list --reverse --first-equal-tree-only --no-merges "$revisions"`
do
msgnum=$(($msgnum + 1))
echo "$cmt" > "$dotest/cmt.$msgnum"
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 6/7] add support for creating equal tree markers after rebase
2009-11-30 14:43 equal-tree-merges as way to make rebases fast-forward-able Bernhard R. Link
` (4 preceding siblings ...)
2009-11-30 14:45 ` [PATCH 5/7] make rebase -m equal tree marker aware Bernhard R. Link
@ 2009-11-30 14:45 ` Bernhard R. Link
2009-11-30 14:45 ` [PATCH 7/7] add support for creating equal tree markers to rebase -i Bernhard R. Link
` (7 subsequent siblings)
13 siblings, 0 replies; 29+ messages in thread
From: Bernhard R. Link @ 2009-11-30 14:45 UTC (permalink / raw)
To: git
With the new --eqt option, git rebase adds an equal tree marker,
so that the old branch can be fast-forwarded to the new one.
If the trees are not equal, a fake merge of the new base and the
old branch is created first.
TODO:
- manpage update,
- should --eqt have a better (longer more descriptive) name?
- the commit message of the merge should have a better default
and presented to the user for editing
---
git-rebase.sh | 33 +++++++++++++++++++++++++++++++--
1 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/git-rebase.sh b/git-rebase.sh
index 391f6d6..681c97b 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -50,6 +50,7 @@ diffstat=$(git config --bool rebase.stat)
git_am_opt=
rebase_root=
force_rebase=
+equal_tree_marker=
continue_merge () {
test -n "$prev_head" || die "prev_head must be defined"
@@ -132,11 +133,30 @@ call_merge () {
esac
}
+# is there really no already existing function for this?
+tree_of_commit() {
+ git cat-file commit "$1" | grep '^tree ' | head -n 1 | sed -e 's/^tree //'
+}
+
move_to_original_branch () {
test -z "$head_name" &&
head_name="$(cat "$dotest"/head-name)" &&
onto="$(cat "$dotest"/onto)" &&
- orig_head="$(cat "$dotest"/orig-head)"
+ orig_head="$(cat "$dotest"/orig-head)" &&
+ equal_tree_marker="$(cat "$dotest"/eqt)"
+ if test t = "$equal_tree_marker" ; then
+ # first apply all the changes to the old branch
+ old_tree=$(tree_of_commit "$orig_head")
+ new_tree=$(tree_of_commit HEAD)
+ if test "$old_tree" = "$new_tree" ; then
+ old_branch="$orig_head"
+ else
+ # TODO: better commit message
+ old_branch=$(echo "rebase $head_name onto $onto" | git-commit-tree $new_tree -p "$orig_head" -p "$onto" )
+ fi
+ # then say the old branch can be upgraded to the new one:
+ git equal-tree-marker "$old_branch"
+ fi
case "$head_name" in
refs/*)
message="rebase finished: $head_name onto $onto"
@@ -220,6 +240,7 @@ do
end=$(cat "$dotest/end")
msgnum=$(cat "$dotest/msgnum")
onto=$(cat "$dotest/onto")
+ equal_tree_marker=$(cat "$dotest/eqt")
GIT_QUIET=$(cat "$dotest/quiet")
continue_merge
while test "$msgnum" -le "$end"
@@ -234,6 +255,7 @@ do
onto=$(cat "$GIT_DIR"/rebase-apply/onto) &&
orig_head=$(cat "$GIT_DIR"/rebase-apply/orig-head) &&
GIT_QUIET=$(cat "$GIT_DIR"/rebase-apply/quiet)
+ equal_tree_marker=$(cat "$GIT_DIR"/rebase-apply/eqt)
git am --resolved --3way --resolvemsg="$RESOLVEMSG" &&
move_to_original_branch
exit
@@ -251,6 +273,7 @@ do
msgnum=$(cat "$dotest/msgnum")
msgnum=$(($msgnum + 1))
onto=$(cat "$dotest/onto")
+ equal_tree_marker=$(cat "$dotest/eqt")
GIT_QUIET=$(cat "$dotest/quiet")
while test "$msgnum" -le "$end"
do
@@ -264,6 +287,7 @@ do
onto=$(cat "$GIT_DIR"/rebase-apply/onto) &&
orig_head=$(cat "$GIT_DIR"/rebase-apply/orig-head) &&
GIT_QUIET=$(cat "$GIT_DIR"/rebase-apply/quiet)
+ equal_tree_marker=$(cat "$GIT_DIR"/rebase-apply/eqt)
git am -3 --skip --resolvemsg="$RESOLVEMSG" &&
move_to_original_branch
exit
@@ -340,6 +364,9 @@ do
git_am_opt="$git_am_opt $1"
force_rebase=t
;;
+ --eqt)
+ equal_tree_marker=t
+ ;;
-C*)
git_am_opt="$git_am_opt $1"
;;
@@ -522,7 +549,8 @@ then
echo $head_name > "$GIT_DIR"/rebase-apply/head-name &&
echo $onto > "$GIT_DIR"/rebase-apply/onto &&
echo $orig_head > "$GIT_DIR"/rebase-apply/orig-head &&
- echo "$GIT_QUIET" > "$GIT_DIR"/rebase-apply/quiet
+ echo "$GIT_QUIET" > "$GIT_DIR"/rebase-apply/quiet &&
+ echo "$equal_tree_marker" > "$GIT_DIR"/rebase-apply/eqt
exit $ret
fi
@@ -537,6 +565,7 @@ echo "$prev_head" > "$dotest/prev_head"
echo "$orig_head" > "$dotest/orig-head"
echo "$head_name" > "$dotest/head-name"
echo "$GIT_QUIET" > "$dotest/quiet"
+echo "$equal_tree_marker" > "$dotest/eqt"
msgnum=0
for cmt in `git rev-list --reverse --first-equal-tree-only --no-merges "$revisions"`
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 7/7] add support for creating equal tree markers to rebase -i
2009-11-30 14:43 equal-tree-merges as way to make rebases fast-forward-able Bernhard R. Link
` (5 preceding siblings ...)
2009-11-30 14:45 ` [PATCH 6/7] add support for creating equal tree markers after rebase Bernhard R. Link
@ 2009-11-30 14:45 ` Bernhard R. Link
2009-11-30 15:10 ` equal-tree-merges as way to make rebases fast-forward-able Sverre Rabbelier
` (6 subsequent siblings)
13 siblings, 0 replies; 29+ messages in thread
From: Bernhard R. Link @ 2009-11-30 14:45 UTC (permalink / raw)
To: git
With the new --eqt option, git rebase -i adds an equal tree marker,
so that the old branch can be fast-forwarded to the new one.
If the trees are not equal, a fake merge of the new base and
the old branch is created first.
TODO:
- manpage update,
- should --eqt have a better (longer more descriptive) name?
- the commit message of the merge should have a better default
and presented to the user for editing
---
git-rebase--interactive.sh | 32 ++++++++++++++++++++++++++++++++
1 files changed, 32 insertions(+), 0 deletions(-)
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 3da9f3e..51cc5fa 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -20,6 +20,7 @@ v,verbose display a diffstat of what changed upstream
onto= rebase onto given branch instead of upstream
p,preserve-merges try to recreate merges instead of ignoring them
s,strategy= use the given merge strategy
+eqt create an equal tree marker to allow f-f from old tree
m,merge always used (no-op)
i,interactive always used (no-op)
Actions:
@@ -46,6 +47,7 @@ ONTO=
VERBOSE=
OK_TO_SKIP_PRE_REBASE=
REBASE_ROOT=
+EQUAL_TREE_MARKER=
GIT_CHERRY_PICK_HELP=" After resolving the conflicts,
mark the corrected paths with 'git add <paths>', and
@@ -325,6 +327,11 @@ peek_next_command () {
sed -n "1s/ .*$//p" < "$TODO"
}
+# is there really no already existing function for this?
+tree_of_commit() {
+ git cat-file commit "$1" | grep '^tree ' | head -n 1 | sed -e 's/^tree //'
+}
+
do_next () {
rm -f "$DOTEST"/message "$DOTEST"/author-script \
"$DOTEST"/amend || exit
@@ -426,6 +433,25 @@ do_next () {
esac
test -s "$TODO" && return
+ if test t = "$(cat "$DOTEST/eqt")" ; then
+ HEADNAME=$(cat "$DOTEST"/head-name)
+ OLDHEAD=$(cat "$DOTEST"/head)
+ ONTO=$(cat "$DOTEST"/onto)
+ NEWHEAD=$(git rev-parse HEAD)
+ OLDTREE=$(tree_of_commit "$OLDHEAD")
+ NEWTREE=$(tree_of_commit HEAD)
+ if test "$NEWTREE" = "$OLDTREE" ; then
+ OLDBRANCH="$OLDHEAD"
+ else
+ echo "Creating commit with differences of '$OLDHEAD' now that is applied to '$ONTO' (tree $NEWTREE)"
+ OLDBRANCH="$( (grep '^# Rebase' "$TODO".full \
+ ; grep -v '^#' "$TODO".full ) \
+ | git-commit-tree "$NEWTREE" \
+ -p "$OLDHEAD" -p "$ONTO")"
+ fi
+ git equal-tree-marker "$OLDBRANCH"
+ fi
+
comment_for_reflog finish &&
HEADNAME=$(cat "$DOTEST"/head-name) &&
OLDHEAD=$(cat "$DOTEST"/head) &&
@@ -605,6 +631,9 @@ first and then run 'git rebase --continue' again."
ONTO=$(git rev-parse --verify "$1") ||
die "Does not point to a valid commit: $1"
;;
+ --eqt)
+ EQUAL_TREE_MARKER=t
+ ;;
--)
shift
test -z "$REBASE_ROOT" -a $# -ge 1 -a $# -le 2 ||
@@ -656,6 +685,7 @@ first and then run 'git rebase --continue' again."
: >"$DOTEST"/rebase-root ;;
esac
echo $ONTO > "$DOTEST"/onto
+ echo "$EQUAL_TREE_MARKER" > "$DOTEST"/eqt
test -z "$STRATEGY" || echo "$STRATEGY" > "$DOTEST"/strategy
test t = "$VERBOSE" && : > "$DOTEST"/verbose
if test t = "$PRESERVE_MERGES"
@@ -787,6 +817,8 @@ EOF
test -d "$REWRITTEN" || skip_unnecessary_picks
+ cp "$TODO" "$TODO".full
+
git update-ref ORIG_HEAD $HEAD
output git checkout $ONTO && do_rest
;;
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: equal-tree-merges as way to make rebases fast-forward-able
2009-11-30 14:43 equal-tree-merges as way to make rebases fast-forward-able Bernhard R. Link
` (6 preceding siblings ...)
2009-11-30 14:45 ` [PATCH 7/7] add support for creating equal tree markers to rebase -i Bernhard R. Link
@ 2009-11-30 15:10 ` Sverre Rabbelier
2009-11-30 15:31 ` Paolo Bonzini
` (5 subsequent siblings)
13 siblings, 0 replies; 29+ messages in thread
From: Sverre Rabbelier @ 2009-11-30 15:10 UTC (permalink / raw)
To: Bernhard R. Link; +Cc: git
Heya,
On Mon, Nov 30, 2009 at 15:43, Bernhard R. Link <brlink@debian.org> wrote:
> Those patches are a bit rough and mostly intended to show how it could work
> and to allow experimenting with it.
Given the experimental nature of your patches it would probably have
been appropriate to mark them "RFC" (request for comment). You can do
so by running: `git format-patch --subject-prefix="RFC PATCH"` instead
of "git format-patch".
--
Cheers,
Sverre Rabbelier
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: equal-tree-merges as way to make rebases fast-forward-able
2009-11-30 14:43 equal-tree-merges as way to make rebases fast-forward-able Bernhard R. Link
` (7 preceding siblings ...)
2009-11-30 15:10 ` equal-tree-merges as way to make rebases fast-forward-able Sverre Rabbelier
@ 2009-11-30 15:31 ` Paolo Bonzini
2009-11-30 16:22 ` Bernhard R. Link
2009-11-30 15:35 ` Michael J Gruber
` (4 subsequent siblings)
13 siblings, 1 reply; 29+ messages in thread
From: Paolo Bonzini @ 2009-11-30 15:31 UTC (permalink / raw)
To: git
On 11/30/2009 03:43 PM, Bernhard R. Link wrote:
> The itch this idea is supposed to scratch is the problem that a rebase
> or a amended commit is no longer a fast-forward, so cannot be easily
> pulled.
How does this compare with topgit?
Paolo
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: equal-tree-merges as way to make rebases fast-forward-able
2009-11-30 15:31 ` Paolo Bonzini
@ 2009-11-30 16:22 ` Bernhard R. Link
0 siblings, 0 replies; 29+ messages in thread
From: Bernhard R. Link @ 2009-11-30 16:22 UTC (permalink / raw)
To: git
* Paolo Bonzini <bonzini@gnu.org> [091130 16:32]:
> On 11/30/2009 03:43 PM, Bernhard R. Link wrote:
>> The itch this idea is supposed to scratch is the problem that a rebase
>> or a amended commit is no longer a fast-forward, so cannot be easily
>> pulled.
>
> How does this compare with topgit?
It's not easily compareable as having different aims, but I think there
are some use-cases where this allows native usage of git where
previously the best bet was topgit.
Assume for example you want to maintain a set of patches of some
upstream, which you want to have in some form relative to upstream
and in patches easily reviewable and pickable by other people.
You could do that with topgit by making each change a topgit branch.
But to clone that repository then you would need topgit to get all
the information and cherry picking one of your changes (that perhaps
grow with the time, was adapted to new upstreams and had bugs fixed)
needs telling topgit to combine the changes of that branch and use that
instead of a simple cherry pick.
With this equal-tree-marker you can just do a git rebase --eqt or git
rebase -i --eqt and both have a history with your changes as single
commits which are easy to look at (and you can just pushing head^1
somewhere for upstream to pull from) while still having all the history
in your git archive so someone else can look what actually happened or
just clone your current head and repeatenly pull from it.
Hochachtungsvoll,
Bernhard R. Link
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: equal-tree-merges as way to make rebases fast-forward-able
2009-11-30 14:43 equal-tree-merges as way to make rebases fast-forward-able Bernhard R. Link
` (8 preceding siblings ...)
2009-11-30 15:31 ` Paolo Bonzini
@ 2009-11-30 15:35 ` Michael J Gruber
2009-11-30 15:59 ` Michael J Gruber
` (3 subsequent siblings)
13 siblings, 0 replies; 29+ messages in thread
From: Michael J Gruber @ 2009-11-30 15:35 UTC (permalink / raw)
To: Bernhard R. Link; +Cc: git
Bernhard R. Link venit, vidit, dixit 30.11.2009 15:43:
> The itch this idea is supposed to scratch is the problem that a rebase
> or a amended commit is no longer a fast-forward, so cannot be easily
> pulled.
Do you mean pushed?
For pull, the state of the branch on the receiving side play a role, of
course.
> While this is not a problem in most workflows, as one can either merge
> or keep everything private and rebase until published, it would be nice
> to have a way for cases in between, where both a clean presentable
> commit order is to be maintained and people (or yourself from different
> repositories) should be able to easily upgrade to newer versions without
> an error-prone not-fast-forward.
>
> My idea to solve this is combining both histories, the rebased/revised
> history and the actualy history, marking with some "equal-tree-merge"
> the point where they have the same result.
> The following mails show some patches to implement this by means of
> a merge where all parents have the same tree and some special casing
> when encountering such a thing. This has the advantage that older git
> version will just see strange merges and may present both histories,
> but otherwise just work.
Without having the time to go through the detailed setup you described
below (sorry), I'm wondering how this differs from what Git calls a
trivial merge? Is it merely about asserting that you merge coinciding
(heads with) trees?
Michael
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: equal-tree-merges as way to make rebases fast-forward-able
2009-11-30 14:43 equal-tree-merges as way to make rebases fast-forward-able Bernhard R. Link
` (9 preceding siblings ...)
2009-11-30 15:35 ` Michael J Gruber
@ 2009-11-30 15:59 ` Michael J Gruber
2009-11-30 16:54 ` Bernhard R. Link
2009-11-30 17:19 ` Johannes Schindelin
` (2 subsequent siblings)
13 siblings, 1 reply; 29+ messages in thread
From: Michael J Gruber @ 2009-11-30 15:59 UTC (permalink / raw)
To: Bernhard R. Link; +Cc: git
Bernhard R. Link venit, vidit, dixit 30.11.2009 15:43:
[...]
Ok, I couldn't resist looking at your examples. Actually, before
anything else: Thanking for describing *what* you want to achieve, not
only how.
> Example 1:
>
> Let's assume you maintain such a regularily-rebased branch that you
> want to be able to publish (or pull from other repositories for example
> on your laptop):
>
> o=m=o=o=master
> \
> a=b=c=d=e=feature
>
> with this patch you can do "git rebase -eqt master" and get:
>
> a'=b'=c'=d'=e'=feature'=eqt
> / /
> o=m=o=o=master-------- /
> \ \ /
> a=b=c=d=e=feature--merge-------
>
git checkout -b featureprime feature
git rebase master
git merge feature # should be trivial
git branch -M featureprime feature
> i.e: the new feature branch has both histories:
> - "feature'" where everything is cleanly rebased and in a form where
> format-patch is suitable to send it upstream
> - "merge" which is both a descendant from feature (so one can see what
> changed since that time and can just pull when one had had cloned feature)
>
> Example 2:
>
> Let's assume you have a feature branch like
>
> o=master
> \
> a=b=c=d=e=f
>
> Assume you just commited "f" which fixes a bug introduced by "b".
> Now you of course do not want to send it that way upstream (as it will
> make reviewing harder, may force people bisecting to skip some versions
> every time they hit this region and so on), so you want to
> bisect -i and squash "f" into "b".
>
> o=master
> \
> a=b+f=c'=d'=e'
>
> But if you had already cloned at state "d" to your laptop (or made a backup
> of that branch at some server, or published it for use of some collegues)
> it will not be a fast-forward, so you have to be very carefull to not
> accidentially lose a commit that is already there.
>
> So with this patches you can do "git rebase -i --eqt" and squash f into b
> and get:
>
> o=master
> \
> a=b=c=d=e=f---
> \ \
> b+f=c'=d'=e'=eqt
>
> which means that you can just pull from your laptop and get the new head
> as fast-forward, but still have a proper history ready for submitting.
If that side branch is named "feature":
git checkout -b fixup feature
git rebase -i a # squash f into b; creates b+f c# d' e'
git merge feature # should be trivial
git branch -M fixup feature
You can also go crazy with rebase --onto here, or use cherry-pick
repeatedly.
Note that I always use a temporary branch for rewriting, before renaming
it to the proper branch name. I haven't checked, but I assume the
"first-parents" are the way you want them (you want log --first-parent
--no-merges to show the rewritten commits, right?); otherwise you would
have to do the merges the other way round.
Cheers,
Michael
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: equal-tree-merges as way to make rebases fast-forward-able
2009-11-30 15:59 ` Michael J Gruber
@ 2009-11-30 16:54 ` Bernhard R. Link
0 siblings, 0 replies; 29+ messages in thread
From: Bernhard R. Link @ 2009-11-30 16:54 UTC (permalink / raw)
Cc: git
* Michael J Gruber <git@drmicha.warpmail.net> [091130 17:00]:
> Bernhard R. Link venit, vidit, dixit 30.11.2009 15:43:
> > o=m=o=o=master
> > \
> > a=b=c=d=e=feature
> >
> > with this patch you can do "git rebase -eqt master" and get:
> >
>
> git checkout -b featureprime feature
> git rebase master
> git merge feature # should be trivial
> git branch -M featureprime feature
> [...]
> Note that I always use a temporary branch for rewriting, before renaming
> it to the proper branch name. I haven't checked, but I assume the
> "first-parents" are the way you want them (you want log --first-parent
> --no-merges to show the rewritten commits, right?); otherwise you would
> have to do the merges the other way round.
My problem with that is that --first-parent-only makes no difference
between this and other merges.
Assume the example2
o=master
\
a=b=c=d=e=f---
\ \
b+f=c'=d'=e'=eqt
would continue with some paralel commits and a merge:
o=master
\
a=b=c=d=e=f--- y
\ \ / \
b+f=c'=d'=e'=eqt-x m
\ /
z
now if you rebase that tree (or want to send it with format-patch),
you either get the old commits multiple times in format-patch
(and possibly causing already resolved conflicts when doing the am
step in rebase), or you use --first-parent-only and might miss z.
Thus the idea to have some way to destinguish this merge from a normal
merge and thus the extra pseudo-merge in example 1 to get the following
merge to merge things with equal tree.
Hochachtungsvoll,
Bernhard R. Link
--
"Never contain programs so few bugs, as when no debugging tools are available!"
Niklaus Wirth
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: equal-tree-merges as way to make rebases fast-forward-able
2009-11-30 14:43 equal-tree-merges as way to make rebases fast-forward-able Bernhard R. Link
` (10 preceding siblings ...)
2009-11-30 15:59 ` Michael J Gruber
@ 2009-11-30 17:19 ` Johannes Schindelin
2009-11-30 18:18 ` Junio C Hamano
2009-12-01 11:50 ` Michael Haggerty
13 siblings, 0 replies; 29+ messages in thread
From: Johannes Schindelin @ 2009-11-30 17:19 UTC (permalink / raw)
To: Bernhard R. Link; +Cc: git
Hi,
On Mon, 30 Nov 2009, Bernhard R. Link wrote:
> The itch this idea is supposed to scratch is the problem that a rebase
> or a amended commit is no longer a fast-forward, so cannot be easily
> pulled.
Actually, I did something like this without any new tool:
git rebase origin/master
git merge -s ours master@{1}
The effect is that there is a merge commit which really merges the old
state.
OTOH I can see that there is merit in trying to avoid to _require_ the
whole history of the rebased branch. But then, would it not be more in
line with Git's ideas if there was a tool trying to identify, say,
from the commit message which commits in HEAD...MERGE_HEAD are
supposed to be identical?
Ciao,
Dscho
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: equal-tree-merges as way to make rebases fast-forward-able
2009-11-30 14:43 equal-tree-merges as way to make rebases fast-forward-able Bernhard R. Link
` (11 preceding siblings ...)
2009-11-30 17:19 ` Johannes Schindelin
@ 2009-11-30 18:18 ` Junio C Hamano
2009-11-30 18:55 ` Bernhard R. Link
` (2 more replies)
2009-12-01 11:50 ` Michael Haggerty
13 siblings, 3 replies; 29+ messages in thread
From: Junio C Hamano @ 2009-11-30 18:18 UTC (permalink / raw)
To: Bernhard R. Link; +Cc: git
"Bernhard R. Link" <brlink@debian.org> writes:
> My idea to solve this is combining both histories, the rebased/revised
> history and the actualy history, marking with some "equal-tree-merge"
> the point where they have the same result.
If you rewrite a series twice, your RFC will work like this, IIUC:
* You have commit 1 and rewrite it to 2. You record the difference
between 1 and 2 on top of 1 as commit X and record a same-tree merge as
A. Here, A^1 == 2, A^2 == X, and 2^{tree} == A^{tree}.
2-------A
/ /
0---1---X
* You then rewrite it to 3. You record the difference between A and 3
(which is the same as between 2 and 3, because 2^{tree} == A^{tree})
as commit Y, and record a same-tree merge as B. B^1 == 3, B^2 == Y and
3^{tree} == B^{tree}.
Y---------------B
/ /
2-------A-------3
/ /
0---1---X
It however might be easier to review what happened if you create a history
this way upon the second rewrite (forget the second picture above):
3-------.
/ \
0---2---W---B
\ /
1-------Z
That is, Z and W records the interdifff between 1 to 3 and 2 to 3
respectively, and B is a same-tree merge of 3, W and Z.
As you are giving some specific meaning to the order of merge parents of a
marker commit, namely, the first parent is the latest version of this
series (i.e. B^1 == 3), you can extend it to declare that the second
parent is the next to the latest incarnation (i.e. B^2 == W) and the third
one is one version older than the second one (i.e. B^3 == Z).
Doing it this way allows you to publish the final result "3" without any
cruft in the history.
In your code you have comment wondering if there is a better wording for
the fix-up commit you create during rebase when the trees do not match. I
would suggest calling it "interdiff". That is exactly what "git show W"
would show.
While I find the primary idea (i.e. keeping the old and new equivalents by
recording a merge of it, and using the first-parent to traverse when you
find such a special merge) reasonable (and as Dscho has pointed out, this
technique is widely used, I suspect---it is an obvious thing to do), I
think we need something stronger than just "this commit merges commits
that happen to have the same trees" as the marker.
Git is designed to work well in an environment where multiple people
produces identical result. A 3-way merge resolves cleanly when both
branches modified a path to the same result (at contents level as well at
path level). If you take this principle to the extreme, you should be
able to merge two branches that were developed independently but still
reached the same conclusion at the end, without marking such a merge as
anything funny. With your RFC code, one branch will be mistakenly treated
as "old cruft that was improved by the other branch by rewriting".
To avoid that, I think (1) the marker has to be more reliable than just
"happens to have the same tree", and (2) the traversal done by Porcelains
(your patches 3 thru 5) by default should be unaware of eqt.
I don't know what a suitable marker should look like, though. The marker
must be easily identifiable by the lowest level rev-list machinery, so it
needs to be a sign left somewhere in the commit object. Perhaps making it
require to have the same tree as all its parents _and_ a well-known marker
string in the log message (and nothing else) would be a good start.
In the longer term, if the line of this direction turns out to be a good
one, I do not mind adding a special header to the commit object separate
from the log message, but we should start without one until this proves to
be a useful ingredient in people's workflows. With a reliable marker, we
can obviously drop the "same-tree" ness from the definition of the marker
commit, which in turn means that you do not need "interdiff" commits while
rebasing.
The command to build such a merge could be an option to "git merge -s ours"
(perhaps something like "git merge -s ours -Xeqt").
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: equal-tree-merges as way to make rebases fast-forward-able
2009-11-30 18:18 ` Junio C Hamano
@ 2009-11-30 18:55 ` Bernhard R. Link
2009-12-01 0:25 ` Junio C Hamano
2009-11-30 19:26 ` Johannes Sixt
2009-11-30 22:12 ` Nanako Shiraishi
2 siblings, 1 reply; 29+ messages in thread
From: Bernhard R. Link @ 2009-11-30 18:55 UTC (permalink / raw)
To: git
* Junio C Hamano <gitster@pobox.com> [091130 19:19]:
> "Bernhard R. Link" <brlink@debian.org> writes:
>
> > My idea to solve this is combining both histories, the rebased/revised
> > history and the actualy history, marking with some "equal-tree-merge"
> > the point where they have the same result.
>
> If you rewrite a series twice, your RFC will work like this, IIUC:
>
> * You have commit 1 and rewrite it to 2. You record the difference
> between 1 and 2 on top of 1 as commit X and record a same-tree merge as
> A. Here, A^1 == 2, A^2 == X, and 2^{tree} == A^{tree}.
>
> 2-------A
> / /
> 0---1---X
>
> * You then rewrite it to 3. You record the difference between A and 3
> (which is the same as between 2 and 3, because 2^{tree} == A^{tree})
> as commit Y, and record a same-tree merge as B. B^1 == 3, B^2 == Y and
> 3^{tree} == B^{tree}.
>
> Y---------------B
> / /
> 2-------A-------3
> / /
> 0---1---X
I think it rather looks like this:
3---------------B
| /
| 2-------A---Y
|/ /
0---1---X
>
> 3-------.
> / \
> 0---2---W---B
> \ /
> 1-------Z
>
> That is, Z and W records the interdifff between 1 to 3 and 2 to 3
> respectively, and B is a same-tree merge of 3, W and Z.
I think changing it to get this would be easy (though only in the case
where the very last commit was such an equal tree merge), but I do not
think it would be actually better:
- it is no longer possible to see the history of changes by just walking
right on every equal-tree-merge.
- commit a no longer exists. If some downstream already has
cloned/pulled, no fast-forward is possible any more.
> While I find the primary idea (i.e. keeping the old and new equivalents by
> recording a merge of it, and using the first-parent to traverse when you
> find such a special merge) reasonable (and as Dscho has pointed out, this
> technique is widely used, I suspect---it is an obvious thing to do), I
> think we need something stronger than just "this commit merges commits
> that happen to have the same trees" as the marker.
I've considered adding a new header or only a magic description text for those
commits, but I think it is not necessary.
Because the actual programs making it useful to treat this special
(format-patch producing too many patches, rebases possibly showing conflicts
already resolved and bisect walking too many branches) will be the same when
two branches only resulting in the same tree by pure chance show up.
> To avoid that, I think (1) the marker has to be more reliable than just
> "happens to have the same tree", and (2) the traversal done by Porcelains
> (your patches 3 thru 5) by default should be unaware of eqt.
I think for patch 3 (format-patch) and 4 (rebase -i) it is always better to
have the new behaviour even when only hitting equal trees by chance.
I'm unsure about 5 (rebase -m), but guess it still is.
> I don't know what a suitable marker should look like, though. The marker
> must be easily identifiable by the lowest level rev-list machinery, so it
> needs to be a sign left somewhere in the commit object. Perhaps making it
> require to have the same tree as all its parents _and_ a well-known marker
> string in the log message (and nothing else) would be a good start.
It already does always create a unique log message. So one could also
have one more strict and one less strict mode (and some option to decide
on the default).
Hochachtungsvoll,
Bernhard R. Link
--
"Never contain programs so few bugs, as when no debugging tools are available!"
Niklaus Wirth
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: equal-tree-merges as way to make rebases fast-forward-able
2009-11-30 18:55 ` Bernhard R. Link
@ 2009-12-01 0:25 ` Junio C Hamano
0 siblings, 0 replies; 29+ messages in thread
From: Junio C Hamano @ 2009-12-01 0:25 UTC (permalink / raw)
To: Bernhard R. Link; +Cc: git
"Bernhard R. Link" <brlink@debian.org> writes:
>> 3-------.
>> / \
>> 0---2---W---B
>> \ /
>> 1-------Z
>>
>> That is, Z and W records the interdifff between 1 to 3 and 2 to 3
>> respectively, and B is a same-tree merge of 3, W and Z.
>
> I think changing it to get this would be easy (though only in the case
> where the very last commit was such an equal tree merge), but I do not
> think it would be actually better:
>
> - it is no longer possible to see the history of changes by just walking
> right on every equal-tree-merge.
> - commit a no longer exists. If some downstream already has
> cloned/pulled, no fast-forward is possible any more.
Oh, I wasn't suggesting you to change it to use an octopus. I however did
want to know if you considered pros-and-cons with such an alternative
(there perhaps are other approaches as well), and I agree recording one
iteration at a time like you do is better.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: equal-tree-merges as way to make rebases fast-forward-able
2009-11-30 18:18 ` Junio C Hamano
2009-11-30 18:55 ` Bernhard R. Link
@ 2009-11-30 19:26 ` Johannes Sixt
2009-11-30 20:32 ` Junio C Hamano
2009-11-30 22:12 ` Nanako Shiraishi
2 siblings, 1 reply; 29+ messages in thread
From: Johannes Sixt @ 2009-11-30 19:26 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Bernhard R. Link, git
On Montag, 30. November 2009, Junio C Hamano wrote:
> To avoid that, I think (1) the marker has to be more reliable than just
> "happens to have the same tree", and (2) the traversal done by Porcelains
> (your patches 3 thru 5) by default should be unaware of eqt.
>
> I don't know what a suitable marker should look like, though. The marker
> must be easily identifiable by the lowest level rev-list machinery, so it
> needs to be a sign left somewhere in the commit object.
Wouldn't the pathspec . be the marker:
git rev-list HEAD -- .
follows only one of the branches that have identical trees.
-- Hannes
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: equal-tree-merges as way to make rebases fast-forward-able
2009-11-30 19:26 ` Johannes Sixt
@ 2009-11-30 20:32 ` Junio C Hamano
0 siblings, 0 replies; 29+ messages in thread
From: Junio C Hamano @ 2009-11-30 20:32 UTC (permalink / raw)
To: Johannes Sixt; +Cc: Junio C Hamano, Bernhard R. Link, git
Johannes Sixt <j6t@kdbg.org> writes:
> On Montag, 30. November 2009, Junio C Hamano wrote:
>> To avoid that, I think (1) the marker has to be more reliable than just
>> "happens to have the same tree", and (2) the traversal done by Porcelains
>> (your patches 3 thru 5) by default should be unaware of eqt.
>>
>> I don't know what a suitable marker should look like, though. The marker
>> must be easily identifiable by the lowest level rev-list machinery, so it
>> needs to be a sign left somewhere in the commit object.
>
> Wouldn't the pathspec . be the marker:
>
> git rev-list HEAD -- .
>
> follows only one of the branches that have identical trees.
Because I am saying that "this commit has two parents and they record the
identical trees" is a condition that is too weak to mark a special-purpose
merge to bind the latest and an earlier version of a series, your rev-list
example command line should not be the way to identify such a mark commit
and act differently upon seeing one.
Actually your command line is even weaker, I think, although it would not
make much difference in real-life. The marker as currently Bernhard
implements not only has parents with identical trees, but the tree it has
also matches those of its parents.
You can make a commit that merges two branches that independently reached
the same conclusion (which git is designed to handle as an ordinary event
in real life), and amend that commit into an evil merge that has different
contents from its parents (which, I suspect, does not have much use in
practice), and your rev-list will drop one of the branches for even such a
commit, mistaking it as a marker when it is clearly not one.
My "it would not make much difference in real-life" in the two paragraphs
above comes purely from "such an evil merge would not have much use in
practice". We should make sure that "two branches that reached the same
conclusion" is not mistaken with a marker this series introduces.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: equal-tree-merges as way to make rebases fast-forward-able
2009-11-30 18:18 ` Junio C Hamano
2009-11-30 18:55 ` Bernhard R. Link
2009-11-30 19:26 ` Johannes Sixt
@ 2009-11-30 22:12 ` Nanako Shiraishi
2009-12-01 0:20 ` Junio C Hamano
2 siblings, 1 reply; 29+ messages in thread
From: Nanako Shiraishi @ 2009-11-30 22:12 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Bernhard R. Link, git
Quoting Junio C Hamano <gitster@pobox.com>
> To avoid that, I think (1) the marker has to be more reliable than just
> "happens to have the same tree", and (2) the traversal done by Porcelains
> (your patches 3 thru 5) by default should be unaware of eqt.
>
> I don't know what a suitable marker should look like, though. The marker
> must be easily identifiable by the lowest level rev-list machinery, so it
> needs to be a sign left somewhere in the commit object. Perhaps making it
> require to have the same tree as all its parents _and_ a well-known marker
> string in the log message (and nothing else) would be a good start.
I think you can record a merge commit that has an unusual
list of parents for this. For example, you can record the
latest version twice, as the first and the second parents,
and make the previous version the third parent. Because
such a merge can't be created with git-merge command, you
can reliably tell that it is an unusual 'marker' merge.
No matter what techinique is used to mark the special
'marker', if it happens in real life for two or more people
who worked independantly to arrive at the same conclusion,
I don't think dismissing it as 'by chance' and discarding
the contribution from the second branch is a good solution.
If git is meant to work smoothly in projects where more than
one person see and accept patches from the same origin, the
condition is not met 'by chance'; the tool is by design
supposed to handle it as a regular situation.
On the other hand, if you made the marker reliable, I think
you don't have to disable this feature by default like you
said in your (2).
As a side note, I have a bug to report. I tried this sequence
of commands to make sure git-merge doesn't record the same
parent twice (the last git-merge is made on the slave branch
and tries to have slave, master and slave as its three
parents).
% git init
% echo hello >world
% git add . ; git commit -m first
% echo again >world
% git commit -a -m master
% git checkout -b slave master^
% echo again >world
% git commit -a -m slave
% git merge master slave
But I got the "usage: ..." error message from git-merge.
--
Nanako Shiraishi
http://ivory.ap.teacup.com/nanako3/
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: equal-tree-merges as way to make rebases fast-forward-able
2009-11-30 22:12 ` Nanako Shiraishi
@ 2009-12-01 0:20 ` Junio C Hamano
2009-12-01 0:23 ` [PATCH] git-merge: a deprecation notice of the ancient command line syntax Junio C Hamano
2009-12-02 10:20 ` equal-tree-merges as way to make rebases fast-forward-able Nanako Shiraishi
0 siblings, 2 replies; 29+ messages in thread
From: Junio C Hamano @ 2009-12-01 0:20 UTC (permalink / raw)
To: Nanako Shiraishi; +Cc: Junio C Hamano, Bernhard R. Link, git
Nanako Shiraishi <nanako3@lavabit.com> writes:
> I think you can record a merge commit that has an unusual
> list of parents for this. For example, you can record the
> latest version twice, as the first and the second parents,
> and make the previous version the third parent. Because
> such a merge can't be created with git-merge command, you
> can reliably tell that it is an unusual 'marker' merge.
That's too ugly a hack, and hints an undesirable attitude that this will
be the last feature that needs such cleverness, without leaving the door
open for others who need similar "magic marker" capability added to commit
objects. The approach will not scale, unless you consider "first and
second parents being the same means it is 'rebased branches magic', and
first, second and third parents being the same means some other matic,
etc." as scalable.
As I said, if the approach this series takes turns out to be useful, it is
Ok to implement it as a new header in the commit object if necessary.
We try very hard to avoid adding random headers to commits because a
commit that records the same history should be named the same way in the
object store namespace and adding random headers will make it easier to
create the same commit with different names, but what we are discussing
is a special purpose pseudo commit and it _is_ a feature that the object
name of a commit, after SHA-1 hashing, is different with and without the
special header in this case.
> No matter what techinique is used to mark the special
> 'marker', if it happens in real life for two or more people
> who worked independantly to arrive at the same conclusion,
> I don't think dismissing it as 'by chance' and discarding
> the contribution from the second branch is a good solution.
> If git is meant to work smoothly in projects where more than
> one person see and accept patches from the same origin, the
> condition is not met 'by chance'; the tool is by design
> supposed to handle it as a regular situation.
I said the same thing, and I agree that two (or more) people creating the
same state should be treated as a normal event. But I am not so sure
about a merge that binds two such histories together. The person who
makes such a merge can go on without making one as far as tree-state is
concerned (i.e. such a merge will result in the same tree with both
parents), and the _only_ reason a merge between the two branches is
created is to cauterize one (or both) of the branches, declare that
everything that happened in the branch is now part of this branch.
In other words, such a merge is an operation to purely affect the history
and not contents.
As J6t pointed out, when we tell the revision walking machinery to limit
by path, we already simplify the history we show to the user, and if path
happens to name the whole tree, such a history is already simplified to
show only one side of the story. So perhaps it is not as grave an offence
to ignore contribution from one side when both of the parents of a merge
record the same tree as I originally thought. It also justifies not
introducing a new header in commits. The implementation of Bernhard's
series might become simpler if it used the trick to use "." pathspec
internally instead of introducing a new traversal option to the revision
machinery.
> On the other hand, if you made the marker reliable, I think
> you don't have to disable this feature by default like you
> said in your (2).
That is true, but as you may be able to tell, I am undecided if the marker
should be _that_ explicit, or should be implicit and the fact that a merge
that whose all parents have the same tree should make it automatically a
marker (iow, I earlier said "misidentify" but now I am wondering if it
makes sense to define any merge with the property an "alternative history
binding marker", no matter how it was created).
> As a side note, I have a bug to report. I tried this sequence
> of commands to make sure git-merge doesn't record the same
> parent twice (the last git-merge is made on the slave branch
> and tries to have slave, master and slave as its three
> parents).
>
> % git init
> % echo hello >world
> % git add . ; git commit -m first
> % echo again >world
> % git commit -a -m master
> % git checkout -b slave master^
> % echo again >world
> % git commit -a -m slave
> % git merge master slave
>
> But I got the "usage: ..." error message from git-merge.
Well, you did not quote the usage string you got, but it should have began
like this:
usage: git merge [options] <remote>...
or: git merge [options] <msg> HEAD <remote>
The parser misinterpreted your request as the latter form (which is
ancient and probably predates your involvement with the git project),
noticed that you did not give any <remote> commit, and then gave the
usage message.
I think we really should start deprecating the ancient form, but the
original sample script using this syntax from Linus was copied by many
people and are still found everywhere, I think, and people may still
use their scripts that were written with the ancient syntax.
In any case, at least this patch will make it start behaving a bit
more sanely.
-- >8 --
Subject: Do not misidentify "git merge foo HEAD" as an old-style invocation
This was misinterpreted as an ancient style "git merge <message> HEAD
<commit> <commit>..." that merges one (or more) <commit> into the current
branch and record the resulting commit with the given message. Then a
later sanity check found that there is no <commit> specified and gave
a usage message.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
diff --git a/builtin-merge.c b/builtin-merge.c
index e95c5dc..e5cf795 100644
--- a/builtin-merge.c
+++ b/builtin-merge.c
@@ -792,7 +792,7 @@ static int suggest_conflicts(void)
static struct commit *is_old_style_invocation(int argc, const char **argv)
{
struct commit *second_token = NULL;
- if (argc > 1) {
+ if (argc > 2) {
unsigned char second_sha1[20];
if (get_sha1(argv[1], second_sha1))
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH] git-merge: a deprecation notice of the ancient command line syntax
2009-12-01 0:20 ` Junio C Hamano
@ 2009-12-01 0:23 ` Junio C Hamano
2009-12-01 3:55 ` Nicolas Pitre
2009-12-02 10:20 ` equal-tree-merges as way to make rebases fast-forward-able Nanako Shiraishi
1 sibling, 1 reply; 29+ messages in thread
From: Junio C Hamano @ 2009-12-01 0:23 UTC (permalink / raw)
To: Nanako Shiraishi; +Cc: Bernhard R. Link, git
The ancient form of git merge command used in the original sample script
has been copied from Linus and are still found everywhere, I think, and
people may still have it in their scripts, but on the other hand, it is so
unintuitive that even people reasonably familiar with git is surprised by
accidentally triggering the support to parse this ancient form.
Gently nudge people to upgrade their script to more recent and readable
style for eventual removal of the original syntax.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
And this is the first step of such a deprecation. Perhaps we start
warning in 1.7.0 and remove it in 1.8.0, or something like that.
builtin-merge.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/builtin-merge.c b/builtin-merge.c
index e5cf795..4cb695e 100644
--- a/builtin-merge.c
+++ b/builtin-merge.c
@@ -789,6 +789,11 @@ static int suggest_conflicts(void)
return 1;
}
+static const char deprecation_warning[] =
+ "'git merge <msg> HEAD <commit>' is deprecated. Please update\n"
+ "your script to use 'git merge -m <msg> <commit>' instead.\n"
+ "In future versions of git, this syntax will be removed.";
+
static struct commit *is_old_style_invocation(int argc, const char **argv)
{
struct commit *second_token = NULL;
@@ -802,6 +806,7 @@ static struct commit *is_old_style_invocation(int argc, const char **argv)
die("'%s' is not a commit", argv[1]);
if (hashcmp(second_token->object.sha1, head))
return NULL;
+ warning(deprecation_warning);
}
return second_token;
}
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH] git-merge: a deprecation notice of the ancient command line syntax
2009-12-01 0:23 ` [PATCH] git-merge: a deprecation notice of the ancient command line syntax Junio C Hamano
@ 2009-12-01 3:55 ` Nicolas Pitre
2009-12-01 4:07 ` Junio C Hamano
0 siblings, 1 reply; 29+ messages in thread
From: Nicolas Pitre @ 2009-12-01 3:55 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Nanako Shiraishi, Bernhard R. Link, git
On Mon, 30 Nov 2009, Junio C Hamano wrote:
> The ancient form of git merge command used in the original sample script
> has been copied from Linus and are still found everywhere, I think, and
> people may still have it in their scripts, but on the other hand, it is so
> unintuitive that even people reasonably familiar with git is surprised by
> accidentally triggering the support to parse this ancient form.
>
> Gently nudge people to upgrade their script to more recent and readable
> style for eventual removal of the original syntax.
>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
>
> And this is the first step of such a deprecation. Perhaps we start
> warning in 1.7.0 and remove it in 1.8.0, or something like that.
If this is going to be removed in the future, then it is already
deprecated. Therefore it is much better to start warning now and not
wait for 1.7.0. There is just no point delaying the advice.
Nicolas
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH] git-merge: a deprecation notice of the ancient command line syntax
2009-12-01 3:55 ` Nicolas Pitre
@ 2009-12-01 4:07 ` Junio C Hamano
0 siblings, 0 replies; 29+ messages in thread
From: Junio C Hamano @ 2009-12-01 4:07 UTC (permalink / raw)
To: Nicolas Pitre; +Cc: Nanako Shiraishi, Bernhard R. Link, git
Nicolas Pitre <nico@fluxnic.net> writes:
> On Mon, 30 Nov 2009, Junio C Hamano wrote:
>
>> The ancient form of git merge command used in the original sample script
>> has been copied from Linus and are still found everywhere, I think, and
>> people may still have it in their scripts, but on the other hand, it is so
>> unintuitive that even people reasonably familiar with git is surprised by
>> accidentally triggering the support to parse this ancient form.
>>
>> Gently nudge people to upgrade their script to more recent and readable
>> style for eventual removal of the original syntax.
>>
>> Signed-off-by: Junio C Hamano <gitster@pobox.com>
>> ---
>>
>> And this is the first step of such a deprecation. Perhaps we start
>> warning in 1.7.0 and remove it in 1.8.0, or something like that.
>
> If this is going to be removed in the future, then it is already
> deprecated. Therefore it is much better to start warning now and not
> wait for 1.7.0. There is just no point delaying the advice.
Very true.
What I am not absolutely sure about is if the presense of the support for
ancient usage hurts people in real life so much that it is better to
remove it than keep it. At least we saw one example of a user (who is not
a novice) getting puzzled by it, but that may not be enough datapoint to
decide with.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: equal-tree-merges as way to make rebases fast-forward-able
2009-12-01 0:20 ` Junio C Hamano
2009-12-01 0:23 ` [PATCH] git-merge: a deprecation notice of the ancient command line syntax Junio C Hamano
@ 2009-12-02 10:20 ` Nanako Shiraishi
2009-12-02 18:03 ` Junio C Hamano
1 sibling, 1 reply; 29+ messages in thread
From: Nanako Shiraishi @ 2009-12-02 10:20 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Bernhard R. Link, git
Quoting Junio C Hamano <gitster@pobox.com> writes:
> I think we really should start deprecating the ancient form, but the
> original sample script using this syntax from Linus was copied by many
> people and are still found everywhere, I think, and people may still
> use their scripts that were written with the ancient syntax.
>
> In any case, at least this patch will make it start behaving a bit
> more sanely.
Thank you; it fixes the bug for me. Do I have to say
Tested-by: Nanako Shiraishi <nanako3@lavabit.com>
to ask you to include it in the new release?
> -- >8 --
> Subject: Do not misidentify "git merge foo HEAD" as an old-style invocation
>
> This was misinterpreted as an ancient style "git merge <message> HEAD
> <commit> <commit>..." that merges one (or more) <commit> into the current
> branch and record the resulting commit with the given message. Then a
> later sanity check found that there is no <commit> specified and gave
> a usage message.
>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
>
> diff --git a/builtin-merge.c b/builtin-merge.c
> index e95c5dc..e5cf795 100644
> --- a/builtin-merge.c
> +++ b/builtin-merge.c
> @@ -792,7 +792,7 @@ static int suggest_conflicts(void)
> static struct commit *is_old_style_invocation(int argc, const char **argv)
> {
> struct commit *second_token = NULL;
> - if (argc > 1) {
> + if (argc > 2) {
> unsigned char second_sha1[20];
>
> if (get_sha1(argv[1], second_sha1))
--
Nanako Shiraishi
http://ivory.ap.teacup.com/nanako3/
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: equal-tree-merges as way to make rebases fast-forward-able
2009-12-02 10:20 ` equal-tree-merges as way to make rebases fast-forward-able Nanako Shiraishi
@ 2009-12-02 18:03 ` Junio C Hamano
0 siblings, 0 replies; 29+ messages in thread
From: Junio C Hamano @ 2009-12-02 18:03 UTC (permalink / raw)
To: Nanako Shiraishi; +Cc: Junio C Hamano, Bernhard R. Link, git
Nanako Shiraishi <nanako3@lavabit.com> writes:
>> In any case, at least this patch will make it start behaving a bit
>> more sanely.
>
> Thank you; it fixes the bug for me. Do I have to say
>
> Tested-by: Nanako Shiraishi <nanako3@lavabit.com>
>
> to ask you to include it in the new release?
>
>> -- >8 --
>> Subject: Do not misidentify "git merge foo HEAD" as an old-style invocation
Thanks for reminding me. I almost forgot that I did that patch.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: equal-tree-merges as way to make rebases fast-forward-able
2009-11-30 14:43 equal-tree-merges as way to make rebases fast-forward-able Bernhard R. Link
` (12 preceding siblings ...)
2009-11-30 18:18 ` Junio C Hamano
@ 2009-12-01 11:50 ` Michael Haggerty
13 siblings, 0 replies; 29+ messages in thread
From: Michael Haggerty @ 2009-12-01 11:50 UTC (permalink / raw)
To: Bernhard R. Link; +Cc: git
Bernhard R. Link wrote:
> Example 1:
>
> Let's assume you maintain such a regularily-rebased branch that you
> want to be able to publish (or pull from other repositories for example
> on your laptop):
>
> o=m=o=o=master
> \
> a=b=c=d=e=feature
>
> with this patch you can do "git rebase -eqt master" and get:
>
> a'=b'=c'=d'=e'=feature'=eqt
> / /
> o=m=o=o=master-------- /
> \ \ /
> a=b=c=d=e=feature--merge-------
Actually, there is more information that can be retained about this
rebase operation. Your scheme records the fact that (a+b+c+d+e+merge)
== (o+o+a'+b'+c'+d'+e'), which is certainly true. But in the process of
rebasing, the user has (implicitly or explicitly) resolved conflicts in
transforming each of the patches a -> a', b -> b', etc. In fact, the
patch a' is itself a merge between a and master; b' is a merge between b
and a'; etc. If you record each of these merges individually, the
result looks like this:
o=m=o=o=master
\ \
\ a'=b'=c'=d'=e'=feature'
\ / / / / /
---a==b==c==d==e==feature
There are advantages to retaining all of this history:
* It faithfully represents intermediate steps of the rebase.
* There is no need for special "merge" and "eqt" merge commits affecting
an arbitrary group of feature patches; each of the rebased patches is
treated identically.
* There is a direct ancestry connection from the "new version" to the
"old version" of each patch; for example, it is easy to see that c' is a
new version of c and to compute the corresponding interdiffs.
* There are situations where the additional info can help git choose
better merge bases in the case of merge/rebases across three or more
repositories. For example, somebody who is developing a subfeature
based on the feature branch can merge/rebase changes from both feature
and master without causing utter chaos.
The "historical" version of the feature branch should be omitted from
most git output as you have suggested, but this would be best
implemented by marking the "historical" ancestor with some extra flag in
each merge commit.
> Example 2:
>
> Let's assume you have a feature branch like
>
> o=master
> \
> a=b=c=d=e=f
>
> Assume you just commited "f" which fixes a bug introduced by "b". [...]
>
> So with this patches you can do "git rebase -i --eqt" and squash f into b
> and get:
>
> o=master
> \
> a=b=c=d=e=f---
> \ \
> b+f=c'=d'=e'=eqt
This case can also record additional information:
o=master
\
a=b===c==d=e=f
\ \ \ \
b+f=c'=d'==e'
Here the new DAG cannot represent *all* ancestry information (namely,
that b+f, c', and d' also include the original patch f), but it does
accurately reflect useful information such as that c' includes c and
that e' includes e and f.
I wrote some blog entries about rebasing-with-history that might be
interesting [1-3].
Michael
[1]
http://softwareswirl.blogspot.com/2009/04/truce-in-merge-vs-rebase-war.html
[2]
http://softwareswirl.blogspot.com/2009/08/upstream-rebase-just-works-if-history.html
[3]
http://softwareswirl.blogspot.com/2009/08/rebase-with-history-implementation.html
^ permalink raw reply [flat|nested] 29+ messages in thread