Как узнать, какая из основных или основных веток существует в репозитории?
Я работаю над сценарием Bash, который выполняет некоторое обслуживание репозитория 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
}