summary refs log tree commit diff
path: root/Completion/Unix
diff options
context:
space:
mode:
Diffstat (limited to 'Completion/Unix')
-rw-r--r--Completion/Unix/Command/_git60
1 files changed, 60 insertions, 0 deletions
diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git
index 1dca28802..9e572e25d 100644
--- a/Completion/Unix/Command/_git
+++ b/Completion/Unix/Command/_git
@@ -5640,6 +5640,66 @@ __git_commit_objects_prefer_recent () {
   __git_recent_commits $argument_array_names || __git_commit_objects
 }
 
+# This function returns in $reply recently-checked-out refs' names, in order
+# from most to least recent.
+(( $+functions[__git_recent_branches__names] )) ||
+__git_recent_branches__names()
+{
+  local -a reflog
+  local reflog_subject
+  local new_head
+  local -A seen
+  reply=()
+
+  reflog=(${(ps:\0:)"$(_call_program reflog git reflog -1000 -z --grep-reflog='\^checkout:\ moving\ from\ ' --pretty='%gs' 2>/dev/null)"})
+  for reflog_subject in $reflog; do
+    new_head=${${=reflog_subject}[4]}
+
+    # Skip values added in previous iterations.
+    if (( ${+seen[$new_head]} )); then
+      continue
+    fi
+    seen[$new_head]="" # value is ignored
+
+    # Filter out hashes, to leave only ref names.
+    if [[ $new_head =~ '^[0-9a-f]{40}$' ]]; then
+      continue
+    fi
+
+    # All checks passed.  Add it.
+    reply+=( $new_head )
+  done
+}
+
+(( $+functions[__git_recent_branches] )) ||
+__git_recent_branches() {
+  local -a branches descriptions
+  local branch description
+  local -a reply
+
+  __git_recent_branches__names \
+  ; for branch in $reply
+  do
+      # ### We'd want to convert all $reply to $descriptions in one shot,
+      # ### with this:
+      # ###     array=("${(ps:\0:)"$(_call_program descriptions git --no-pager log --no-walk=unsorted -z --pretty=%s ${(q)reply} --)"}")
+      # ### , but git croaks if any of the positional arguments is a ref name
+      # ### that has been deleted.  (So does 'git rev-parse'.)
+      # ### Hence, we resort to fetching the descriptions one-by-one.
+      # ### This would be costly if fork() is expensive.
+      description="$(_call_program description git --no-pager log --no-walk=unsorted --pretty=%s ${(q)branch} --)"
+
+      # If the ref has been deleted, $description would be empty.
+      if [[ -n "$description" ]]; then
+        branches+=$branch
+        descriptions+="${branch//:/\:}:${description}"
+      fi
+  done
+
+  _describe -V -t recent-branches "recent branches" descriptions branches
+}
+
+
 (( $+functions[__git_commits] )) ||
 __git_commits () {
   local -a argument_array_names