]> gitweb.fluxo.info Git - utils-git.git/commitdiff
Refactor checkout branch scripts
authorSilvio Rhatto <rhatto@riseup.net>
Thu, 23 Nov 2017 13:53:51 +0000 (11:53 -0200)
committerSilvio Rhatto <rhatto@riseup.net>
Thu, 23 Nov 2017 13:53:51 +0000 (11:53 -0200)
git-checkout-branch [new file with mode: 0755]
git-submodule-checkout-branch [deleted file]
git-submodules-checkout-branch [moved from git-submodules-checkout-branches with 62% similarity]

diff --git a/git-checkout-branch b/git-checkout-branch
new file mode 100755 (executable)
index 0000000..625cbd1
--- /dev/null
@@ -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
diff --git a/git-submodule-checkout-branch b/git-submodule-checkout-branch
deleted file mode 100755 (executable)
index 6613bf4..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/bash
-#
-# Checkout branche a submodule.
-#
-
-# 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 the first remote branch that contains our commit
-    #
-    # 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 topic branch in the form of "feature/"? The "develop" branch?
-    local branch="`git branch -r --contains $commit 2> /dev/null | grep -v 'HEAD' | head -1 | sed -e 's|^[^/]*/||'`"
-
-    # Checkout to the given commit
-    if [ ! -z "$branch" ]; then
-      git checkout $branch
-    else
-      echo "$BASENAME: no such branch containing dangling commit $commit"
-    fi
-  fi
-}
-
-# Dispatch
-checkout_branch
similarity index 62%
rename from git-submodules-checkout-branches
rename to git-submodules-checkout-branch
index f254ca9c2478700a916c05ee869b1510caa0bfcb..773ab2178cd71f70fa2e516bb16a5537ebccac42 100755 (executable)
@@ -4,4 +4,4 @@
 #
 
 # Run recursivelly for each submodule
-git submodule foreach --recursive git-submodule-checkout-branch
+git submodule foreach --recursive git-checkout-branch