Как узнать, какая из основных или основных веток существует в репозитории?

Я работаю над сценарием Bash, который выполняет некоторое обслуживание репозитория Git. Некоторые репозитории используют в качестве основной ветви, в то время как другие используют . Какую команду Git можно использовать для возврата первой из существующих веток?

6 ответов

Чтобы узнать, какая из двух локальных веток существует, вы можете использоватьgit branch с -l/ --list аргумент:

      git branch -l master main  # outputs 'master' or 'main', provided only one exists

Чтобы узнать, что есть в другом репозитории Git HEAD есть, используйте:

      $ git ls-remote --symref origin HEAD
ref: refs/heads/master  HEAD
670b81a890388c60b7032a4f5b879f2ece8c4558    HEAD

Это предполагает, что и ваш Git, и удаленный Git не настолько стары, чтобы не поддерживать --symref(он должен поддерживаться с двух сторон). Обратите внимание, что эту команду можно запустить вне любого репозитория, используя напрямую URL-адрес вместо удаленного имени, например origin.

Чтобы узнать, какие имена веток существуют в каком-либо другом репозитории Git, либо клонируйте его и просмотрите полученные имена удаленного отслеживания, либо используйте git ls-remote. Обратите внимание, что вы можете указать только refs/heads чтобы ограничить вывод только именами веток или полностью опустить его, чтобы получить все (все имена ветвей и тегов, а также любые другие имена, которые они выбирают для раскрытия).

Какую команду Git можно использовать для возврата первой из существующих веток?

git branch -r возвращает список пультов.
grep origin/ma будет соответствовать main а также master.
Если вам нужно быть более разборчивым, используйте grep -E 'origin/(main|master)'

Назначение списка, возвращаемого массиву, должно работать, но будьте осторожны с именами файлов с пробелами и c, потому что элементы массива разделены пробелами, и все это может взорваться.

      b=( $(git branch -r | grep origin/ma ) ) # all matches
git checkout "${b[0]##*/}"               # first hit

Если вы хотите быть немного осторожнее,

      for n in main master; do 
  b="$(git branch -r -l "origin/$n")"
  if [[ -n "$b" ]]; then
    git checkout "${b[0]##*/}"
    break # keep the first success
  fi 
done 
   

Что ж, «ветвь по умолчанию» не имеет значения локально; это имеет смысл только в том случае, если ваше репо является удаленным для кого-то еще или с точки зрения удаленного, который размещен кем-то другим. (Кроме того, с точки зрения того, «какую ветку я извлекаю по умолчанию, когда я извлекаю из этой локальной ветки, но если бы вы знали это, вы бы не спрашивали об этом.)

      git fetch
git branch -r --list 'origin/HEAD' | grep '>'

Я хочу проверить локальные ветки репо, так как всегда будет локальная или ветвь

Принимая это как надежное описание вашей предполагаемой среды прецедента, поскольку в общем случае это достаточно часто неверно,

Какую команду Git я могу использовать, чтобы вернуть первую существующую ветку?

Краткий способ сделать это

      if git cat-file -e refs/heads/master 2>&-; then echo master
elif git cat-file -e refs/heads/main 2>&-; then echo main
fi

но для чего-то еще более сложного вам, вероятно, понадобится for-each-ref,

      { git for-each-ref --format='%(refname)' refs/{heads,remotes/*}/master;
  git for-each-ref --format='%(refname)' refs/{heads,remotes/*}/main;
} | sed -E 's,(.*)/,\1 ,' | sort -usk1,1

который дает ответ для локальных веток и всех отслеживаемых пультов без каких-либо foofaraw.

В моемgitрепо это отчетыrefs/remotes/origin master, например, а проект Git сохраняет имена обеих веток в строгом соответствии. Но, как заметил кто-то другой, некоторые проекты хранят записи о том, где они были, когда они отключились, и, как вы могли заметить, у меня нетmasterилиmainветвь. Мойmakeответвленияorigin/next, это тот, из которого я запускаю свои развертывания, и есть пара других для небольших проектов.

Делать только локальные ветки

      { git for-each-ref --format='%(refname:short)' refs/heads/master;
  git for-each-ref --format='%(refname:short)' refs/heads/main;
} | head -1

См . for-each-refПримеры , он был построен для этого.

Мне нужен был скрипт, который работал бы с несколькими удаленными серверами (форк-источник или канонический апстрим) и репозиториями, использующими основной или основной. Основываясь на ответе Пола Ходжеса, я получил:

      #Update local/fork default to match remote. Can also delete current local branch using -D (to clean up a finished feature branch)
gum(){
  REMOTES=( $(git branch -r | grep -Eo "  (origin|upstream)/(master|main)") )
  RNAME=${REMOTES[-1]%%/*}    # Prefix of last one in the list (prefer fetching from upstream over origin)
  RBRANCH=${REMOTES[-1]##*/}  # Suffix of last matching remote
  LBRANCH="$(git rev-parse --abbrev-ref HEAD)"  # Name of current checked out branch

  if [[ "$LBRANCH" != "$RBRANCH" && "$1" != "-D" ]]; then
    echo "error current branch is '$LBRANCH' not $RBRANCH and -D not specified to delete current branch"
  elif [[ ! -z $(git status -s) ]]; then
    echo "error pending changes on local branch"
  else
    # Switch to local default, delete current if requested
    if [[ "$LBRANCH" != "$RBRANCH" && "$1" == "-D" ]]; then
      git checkout $RBRANCH
      git branch -D $LBRANCH
    fi
    # fetch all and prune, then update local default
    git fetch --all -p && git merge $RNAME/$RBRANCH && if [[ "$RNAME" != "origin" ]]; then
      git push ${REMOTES[0]%%/*} $RBRANCH # also update default branch on fork
    fi
  fi
}
Другие вопросы по тегам