[TopGit PATCH] t/depend-add-using-export

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When dependencies can be removed as well as added, tg depend add
needs to make sure that the new dependency can bring in changes
from a branch that has previously been removed as a dependency
from the current TopGit branch.

This implementation uses an exported branch set up by tg export,
and merges the new dependency into the commit that corresponds to
the current base. Using the exported branch in the merge has the
advantage that removed dependencies do not appear as parents, and
the merge base selected by git merge does not include changes from
a removed dependency. As a result, these changes can be merged in
again if the new dependency brings in these changes.

The tree of the merge commit is then used to create the next
commit on the TopGit base branch.

Uwe Kleine-König had the idea to use tg export here.

Signed-off-by: Olaf Dabrunz <odabrunz@xxxxxxx>

---

This is an experimental implementation. It did not get much testing, mainly
because testing ran into a fatal "tg export" bug with my test repository. "tg
export" could be convinced to continue past the error with "bash -x", and that
is how this patch was tested.

This is also my first feature patch for TopGit, so I expect people to have
comments.

Known issues:
    - .top* files in the base should probably be excluded with pretty_tree
    - handle tg export producing zero commits for a dependency


 tg-depend.sh |   80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 80 insertions(+), 0 deletions(-)

diff --git a/tg-depend.sh b/tg-depend.sh
index 474ccda..4d1572d 100644
--- a/tg-depend.sh
+++ b/tg-depend.sh
@@ -60,6 +60,86 @@ depend_add()
 	grep -F -x -e "$name" "$root_dir/.topdeps" >/dev/null &&
 		die "tg: $current_name already depends on $name"
 
+	tmp_export="_tg_tmp/tg_depend"
+	trap 'git branch -D "$tmp_export" 2>/dev/null || true' EXIT
+
+	# Create a separate history that does not contain parent pointers to
+	# removed dependencies. This makes sure that these dependencies can
+	# come in again if any of them were merged into the new dependency.
+	# (I.e., not having any parents leading to removed deps makes sure that
+	# "git merge new_dep" selects a merge base that does not already
+	# include the removed dependencies.)
+
+	# tg export sets up a branch with the following properties:
+	#   - For each of the exported TopGit branch and it's recursive TopGit
+	#     dependencies, zero, one or two commits are created. If there is
+	#     more than one dependency, one commit is created that contains the
+	#     tree from the tip of the base branch (i.e., the merge of all
+	#     current dependencies). If the TopGit patch branch is non-empty,
+	#     another commit contains the collapsed patch.
+	#   - Only current dependencies from .topdeps are considered; removed
+	#     dependencies are not part of the history of the branch.
+	#   - The .top* files are removed.
+	#
+	# tg export bails if the TopGit branch is not up-to-date.
+	$tg export "$tmp_export" || exit
+
+	# Now checkout the commit representing the base of the current branch
+	# in the export, and use that to merge in the new dep, resulting in the
+	# new base tree.
+	# FIXME: also handle the zero commits case -- does TopGit actually make
+	#        that case possible?
+	if branch_empty "$current_name"; then
+		# There is no patch commit. Use tmp_export directly.
+		git checkout -q "$tmp_export"
+	else
+		# Set $tmp_export to it's parent commit, which has the merged
+		# deps without the current patch on top, and check that out.
+		# FIXME: keep the tree of the HEAD commit with the collapsed
+		# patch / new dep merge resolution and use it in the commit on
+		# the patch branch, instead of running tg update? -- this would
+		# re-use conflict resolutions (and other changes) -- but would
+		# git rerere not kick in anyway?
+		git update-ref "refs/heads/$tmp_export" "$tmp_export^"
+		git checkout -q "$tmp_export"
+	fi
+
+	# merge the new dependency into the temp export
+	if ! git merge "$name"; then
+		# open up a shell to work on the conflict
+		info "You are in a subshell. If you abort the merge,"
+		info "use \`exit 1\` to abort adding the dependency."
+		if ! sh -i </dev/tty; then
+			info "Ok, you aborted the merge. Now, you just need to"
+			info "switch back to some sane branch using \`git checkout\`."
+			exit 3
+		fi
+	fi
+
+	# commit the tree of the complete dependency merge on top of the base branch
+	# git-commit-tree $tree -p $topgitbasebranch -p $newdep
+	new_commit="$(
+		echo "Merge branch '$name' into refs/top-bases/$current_name" |
+		git commit-tree "$tmp_export^{tree}" -p "refs/top-bases/$current_name" -p "$name")"
+
+	git update-ref "refs/top-bases/$current_name" "$new_commit"
+
+	# now update the patch branch
+	git checkout -q "$current_name"
+
+	# TODO: improve .topfiles handling by merging them specially
+	# (not always with topgit's "ours" strategy):
+	#   - when merging deps, which may include topgit branches,
+	#	- .topmsg must not be changed: use "ours", or drop the file in
+	#	                               the base branch altogether
+	#	- .topdeps information from deps is irrelevant to the current
+	#	  branch: use "ours", or drop the file in the base branch
+	#   - when merging the base branch into the patch branch, "ours" is ok,
+	#     for the same reasons as above
+	#   - when merging from collaborator's branches (git pull or push
+	#     from/to a remote), do a real merge ("recursive"): the
+	#     collaborator's changes matter on this branch level (TODO)
+
 	echo "$name" >>"$root_dir/.topdeps"
 	git add -f "$root_dir/.topdeps"
 	git commit -m"New TopGit dependency: $name"
-- 
tg: (9404aa1..) t/depend-add-using-export (depends on: master)

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]