aboutsummaryrefslogtreecommitdiff
path: root/git-checkout-branch
diff options
context:
space:
mode:
authorSilvio Rhatto <rhatto@riseup.net>2017-11-23 11:53:51 -0200
committerSilvio Rhatto <rhatto@riseup.net>2017-11-23 11:53:51 -0200
commit77323523c9aed412bf119bf7b827ce7f53350c77 (patch)
tree67f7ec6f5d7f823638b8e94fdc7997aef1b70d74 /git-checkout-branch
parentdb8aaf5f8f0886c8aad9abfc504685e49e70b39c (diff)
downloadutils-git-77323523c9aed412bf119bf7b827ce7f53350c77.tar.gz
utils-git-77323523c9aed412bf119bf7b827ce7f53350c77.tar.bz2
Refactor checkout branch scripts
Diffstat (limited to 'git-checkout-branch')
-rwxr-xr-xgit-checkout-branch88
1 files changed, 88 insertions, 0 deletions
diff --git a/git-checkout-branch b/git-checkout-branch
new file mode 100755
index 0000000..625cbd1
--- /dev/null
+++ b/git-checkout-branch
@@ -0,0 +1,88 @@
+#!/bin/bash
+#
+# Checkout branche a submodule.
+#
+# Searches a branch whose latest commit is the given branch and checkout to
+# that branch.
+#
+# Intended to run only in development environments. In production, always use
+# "git submodule update" only.
+#
+# There are a git-submodule feature to help tracking subdmoule branches:
+#
+# Git submodules: Specify a branch/tag - Stack Overflow
+# https://stackoverflow.com/questions/1777854/git-submodules-specify-a-branch-tag
+#
+# But note that using "git submodule add -b" coupled with "git submodule update --remote"
+# does not leverage the additional security of using the commit ID of the submodule's
+# commit recoreded in the parent commit.
+#
+# Given that the benefits of using git-submodule is both tracking sub-repository state
+# and ensuring a basic integrity check on it's contents, the following implementation
+# is different from the sollution given by the article above by ensuring we only checkout
+# to the branch if it's latest commit is the one having the revision recorded by the parent
+# repository.
+
+# Parameters
+BASENAME="`basename $0`"
+
+# Checkout the branch containing a commit
+function checkout_branch {
+ # Check if we are in a detached HEAD
+ if git branch | grep -q '* (HEAD detached'; then
+ # Determine the commit we're in
+ local commit="`git log -n 1 | head -1 | cut -d ' ' -f 2`"
+
+ # Get all branches were the commit occurs
+ local branches="`git branch -r --contains $commit 2> /dev/null | grep -v 'HEAD'`"
+
+ # Get the first branch whose last commit is our commit
+ if [ ! -z "$branches" ]; then
+ for branch in $branches; do
+ branch_commit="`git log $branch -1 | head -1 | cut -d ' ' -f 2`"
+
+ # In the future some criteria might be stablished to determine how to decide
+ # if the comment is present in more than one branch. Which one to prioritize?
+ #
+ # - A branch recorded in `config -f $toplevel/.gitmodules submodule.$name.branch`?
+ # - A topic branch in the form of "feature/"?
+ # - The "develop" branch?
+ #
+ # This whole business is getting too complicated!
+ if [ "$commit" == "$branch_commit" ]; then
+ # Remove an eventual remote name from branch name
+ local_branch="`echo $branch | sed -e 's|^[^/]*/||'`"
+
+ # Get the commit of the local branch for the case the matching branch is a remote one
+ if git branch | grep -q " $local_branch$"; then
+ local_commit="`git log $local_branch -1 | head -1 | cut -d ' ' -f 2`"
+ else
+ # Branch does not exist
+ local_commit="$branch_commit"
+ fi
+
+ # Checkout to the given commit
+ #
+ # Note that there's space for a race condition here during this
+ # checkout and the merge from the next statement block.
+ #
+ # So be careful and use this script just in development.
+ git checkout $local_branch
+
+ # Update the local branch if needed
+ if [ "$branch_commit" != "$local_commit" ]; then
+ git merge $branch
+ fi
+
+ # Done
+ break
+ fi
+ done
+ else
+ echo "$BASENAME: no such branch containing $commit as it's latest commit"
+ fi
+ fi
+}
+
+# Dispatch
+checkout_branch