Development Tip

하나의 명령으로 git 루트 디렉토리를 얻는 방법이 있습니까?

yourdevel 2020. 10. 2. 23:22
반응형

하나의 명령으로 git 루트 디렉토리를 얻는 방법이 있습니까?


Mercurial에는 다음을 통해 루트 디렉토리 (.hg 포함)를 인쇄하는 방법이 있습니다.

hg root

.git 디렉토리가 포함 된 디렉토리를 가져 오는 것과 동등한 것이 git에 있습니까?


예:

git rev-parse --show-toplevel

참고 : 하위 모듈에서는 상위 저장소가 아닌 하위 모듈의 루트 디렉토리를 표시합니다. Git> = 2.13 이상을 사용하는 경우 서브 모듈이 수퍼 프로젝트의 루트 디렉토리를 표시 할 수있는 방법이 있습니다. 귀하의 자식이 그보다 오래된 경우이 다른 답변을 참조하십시오.


에 대한 man페이지 git-config( Alias 아래 ) 내용 :

별칭 확장에 느낌표가 접두사로 붙으면 쉘 명령으로 처리됩니다. [...] 쉘 명령은 저장소의 최상위 디렉토리에서 실행되며 반드시 현재 디렉토리가 아닐 수도 있습니다.

따라서 UNIX에서는 다음을 수행 할 수 있습니다.

git config --global --add alias.root '!pwd'

했습니다 --show-toplevel최근에 추가 된 git rev-parse또는 왜 아무도 그것을 언급하지?

로부터 git rev-parse매뉴얼 페이지

   --show-toplevel
       Show the absolute path of the top-level directory.

" git rev-parse --git-dir"는 어떻습니까?

F:\prog\git\test\copyMerge\dirWithConflicts>git rev-parse --git-dir
F:/prog/git/test/copyMerge/.git

--git-dir옵션이 작동하는 것 같다.

에서 자식 레브 - 구문 분석 매뉴얼 페이지 :

--git-dir

    Show $GIT_DIR if defined else show the path to the .git directory.

git setup-sh스크립트 에서 실제로 작동하는 것을 볼 수 있습니다 .

Git> = 2.13 하위 모듈 폴더에있는 경우 다음을 사용하십시오 .

git rev-parse --show-superproject-working-tree

여기에 간단한 답을 쓰려면

git root

작업을 수행하려면 다음을 사용하여 git을 구성하십시오.

git config --global alias.root "rev-parse --show-toplevel"

다음을 추가 할 수 있습니다 ~/.bashrc.

alias cdroot='cd $(git root)'

cdroot리포지토리의 맨 위로 이동하는 데 사용할 수 있습니다 .


이미 최상위 수준에 있거나 git 저장소에 있지 않은 경우 cd $(git rev-parse --show-cdup)집으로 데려다 줄 것입니다 (cd). cd ./$(git rev-parse --show-cdup)그것을 고치는 한 가지 방법입니다.


다른 사람들이 언급했듯이 솔루션의 핵심은 git rev-parse --show-cdup. 그러나 해결해야 할 몇 가지 예외적 인 경우가 있습니다.

  1. cwd가 이미 작업 트리의 루트 인 경우 명령은 빈 문자열을 생성합니다.
    실제로는 빈 줄을 생성하지만 명령 대체는 후행 줄 바꿈을 제거합니다. 최종 결과는 빈 문자열입니다.

    대부분의 답변 ./은 빈 출력이 "./"공급되기 전에 빈 출력이되도록 출력을 앞에 붙일 것을 제안 합니다 cd.

  2. GIT_WORK_TREE가 cwd의 상위가 아닌 위치로 설정되면 출력은 절대 경로 이름이 될 수 있습니다.

    ./이 상황에서는 준비 가 잘못되었습니다. a ./가 절대 경로 앞에 추가되면 상대 경로가됩니다 (cwd가 시스템의 루트 디렉토리 인 경우에만 동일한 위치를 참조 함).

  3. 출력에는 공백이 포함될 수 있습니다.

    이것은 실제로 두 번째 경우에만 적용되지만 쉽게 수정할 수 있습니다. 명령 대체 (및 값의 후속 사용)를 큰 따옴표로 묶습니다.

다른 답변에서 언급했듯이 우리는 할 수 cd "./$(git rev-parse --show-cdup)"있지만 두 번째 경우 (큰 따옴표를 생략하면 세 번째 경우)에서 중단됩니다.

많은 쉘 cd ""이 no-op으로 취급 하므로 이러한 쉘에 대해 우리가 할 수 있습니다 cd "$(git rev-parse --show-cdup)"(큰 따옴표는 첫 번째 가장자리의 경우 빈 문자열을 인수로 보호하고 세 번째 가장자리의 경우 공백을 유지합니다). POSIX는의 결과 cd ""가 지정되지 않았다고 말 하므로 이러한 가정을 피하는 것이 가장 좋습니다.

위의 모든 경우에서 작동하는 솔루션에는 일종의 테스트가 필요합니다. 명시 적으로 완료하면 다음과 같이 보일 수 있습니다.

cdup="$(git rev-parse --show-cdup)" && test -n "$cdup" && cd "$cdup"

cd첫 번째 엣지 케이스에 대해서는 아니오 입니다.

cd .첫 번째 엣지 케이스에 대해 실행하는 것이 허용되는 경우 매개 변수 확장에서 조건부를 수행 할 수 있습니다.

cdup="$(git rev-parse --show-cdup)" && cd "${cdup:-.}"

현재 git 루트 디렉토리의 절대 경로를 계산하려면, 예를 들어 쉘 스크립트에서 사용하려면 다음과 같은 readlink 및 git rev-parse 조합을 사용하십시오.

gitroot=$(readlink -f ./$(git rev-parse --show-cdup))

git-rev-parse --show-cdupcwd에서 루트로 이동하기 위해 올바른 수의 ".."을 제공하거나 루트에있는 경우 빈 문자열을 제공합니다. 그런 다음 앞에 "./"를 추가하여 빈 문자열 대소 문자를 처리하고 사용 readlink -f하여 전체 경로로 변환합니다.

git-root이 기술을 적용하기 위해 PATH에 쉘 스크립트로 명령을 작성할 수도 있습니다 .

cat > ~/bin/git-root << EOF
#!/bin/sh -e
cdup=$(git rev-parse --show-cdup)
exec readlink -f ./$cdup
EOF
chmod 755 ~/bin/git-root

(위의 내용을 터미널에 붙여 넣어 git-root를 만들고 실행 비트를 설정할 수 있습니다. 실제 스크립트는 2, 3, 4 행에 있습니다.)

그리고 나서 git root현재 나무의 뿌리를 얻기 위해 달릴 수 있습니다 . 쉘 스크립트에서 "-e"를 사용하여 rev-parse가 실패하면 쉘이 종료되도록하여 git 디렉토리에 있지 않은 경우 종료 상태 및 오류 메시지를 올바르게 가져올 수 있습니다.


이 경로를 Git 자체에 제공하는 경우를 대비하여 :/

# this adds the whole working tree from any directory in the repo
git add :/

# and is equal to
git add $(git rev-parse --show-toplevel)

Short solutions that work with submodules, in hooks, and inside the .git directory

Here's the short answer that most will want:

r=$(git rev-parse --git-dir) && r=$(cd "$r" && pwd)/ && echo "${r%%/.git/*}"

This will work anywhere in a git working tree (including inside the .git directory), but assumes that repository directory(s) are called .git (which is the default). With submodules, this will go to the root of the outermost containing repository.

If you want to get to the root of the current submodule use:

echo $(r=$(git rev-parse --show-toplevel) && ([[ -n $r ]] && echo "$r" || (cd $(git rev-parse --git-dir)/.. && pwd) ))

To easily execute a command in your submodule root, under [alias] in your .gitconfig, add:

sh = "!f() { root=$(pwd)/ && cd ${root%%/.git/*} && git rev-parse && exec \"$@\"; }; f"

This allows you to easily do things like git sh ag <string>

Robust solution that supports differently named or external .git or $GIT_DIR directories.

Note that $GIT_DIR may point somewhere external (and not be called .git), hence the need for further checking.

Put this in your .bashrc:

# Print the name of the git working tree's root directory
function git_root() {
  local root first_commit
  # git displays its own error if not in a repository
  root=$(git rev-parse --show-toplevel) || return
  if [[ -n $root ]]; then
    echo $root
    return
  elif [[ $(git rev-parse --is-inside-git-dir) = true ]]; then
    # We're inside the .git directory
    # Store the commit id of the first commit to compare later
    # It's possible that $GIT_DIR points somewhere not inside the repo
    first_commit=$(git rev-list --parents HEAD | tail -1) ||
      echo "$0: Can't get initial commit" 2>&1 && false && return
    root=$(git rev-parse --git-dir)/.. &&
      # subshell so we don't change the user's working directory
    ( cd "$root" &&
      if [[ $(git rev-list --parents HEAD | tail -1) = $first_commit ]]; then
        pwd
      else
        echo "$FUNCNAME: git directory is not inside its repository" 2>&1
        false
      fi
    )
  else
    echo "$FUNCNAME: Can't determine repository root" 2>&1
    false
  fi
}

# Change working directory to git repository root
function cd_git_root() {
  local root
  root=$(git_root) || return # git_root will print any errors
  cd "$root"
}

Execute it by typing git_root (after restarting your shell: exec bash)


To amend the "git config" answer just a bit:

git config --global --add alias.root '!pwd -P'

and get the path cleaned up. Very nice.


If you're looking for a good alias to do this plus not blow up cd if you aren't in a git dir:

alias ..g='git rev-parse && cd "$(git rev-parse --show-cdup)"'

git-extras

adds $ git root
see https://github.com/tj/git-extras/blob/master/Commands.md#git-root

$ pwd
.../very-deep-from-root-directory
$ cd `git root`
$ git add . && git commit

Availability of git-extras


This shell alias works whether you are in a git subdir, or at the top level:

alias gr='[ ! -z `git rev-parse --show-toplevel` ] && cd `git rev-parse --show-toplevel || pwd`'

updated to use modern syntax instead of backticks:

alias gr='[ ! -z $(git rev-parse --show-toplevel) ] && cd $(git rev-parse --show-toplevel || pwd)'

alias git-root='cd \`git rev-parse --git-dir\`; cd ..'

Everything else fails at some point either going to the home directory or just miserably failing. This is the quickest and shortest way to get back to the GIT_DIR.


Here is a script that I've written that handles both cases: 1) repository with a workspace, 2) bare repository.

https://gist.github.com/jdsumsion/6282953

git-root (executable file in your path):

#!/bin/bash
GIT_DIR=`git rev-parse --git-dir` &&
(
  if [ `basename $GIT_DIR` = ".git" ]; then
    # handle normal git repos (with a .git dir)
    cd $GIT_DIR/..
  else
    # handle bare git repos (the repo IS a xxx.git dir)
    cd $GIT_DIR
  fi
  pwd
)

Hopefully this is helpful.


$ git config alias.root '!pwd'
# then you have:
$ git root

Since Git 2.13.0, it supports a new option to show the path of the root project, which works even when being used from inside a submodule:

git rev-parse --show-superproject-working-tree

Pre-Configured Shell Aliases in Shell Frameworks

If you use a shell framework, there might already be a shell alias available:

  • $ grt in oh-my-zsh (68k) (cd $(git rev-parse --show-toplevel || echo "."))
  • $ git-root in prezto (8.8k) (displays the path to the working tree root)
  • $ g.. zimfw (1k) (changes the current directory to the top level of the working tree.)

I wanted to expand upon Daniel Brockman's excellent comment.

Defining git config --global alias.exec '!exec ' allows you to do things like git exec make because, as man git-config states:

If the alias expansion is prefixed with an exclamation point, it will be treated as a shell command. [...] Note that shell commands will be executed from the top-level directory of a repository, which may not necessarily be the current directory.

It's also handy to know that $GIT_PREFIX will be the path to the current directory relative to the top-level directory of a repository. But, knowing it is only half the battle™. Shell variable expansion makes it rather hard to use. So I suggest using bash -c like so:

git exec bash -c 'ls -l $GIT_PREFIX'

other commands include:

git exec pwd
git exec make

In case anyone needs a POSIX compliant way of doing this, without needing git executable:

git-root:

#$1: Path to child directory
git_root_recurse_parent() {
    # Check if cwd is a git root directory
    if [ -d .git/objects -a -d .git/refs -a -f .git/HEAD ] ; then
        pwd
        return 0
    fi

    # Check if recursion should end (typically if cwd is /)
    if [ "${1}" = "$(pwd)" ] ; then
        return 1
    fi

    # Check parent directory in the same way
    local cwd=$(pwd)
    cd ..
    git_root_recurse_parent "${cwd}"
}

git_root_recurse_parent

If you just want the functionality as part of a script, remove the shebang, and replace the last git_root_recurse_parent line with:

git_root() {
    (git_root_recurse_parent)
}

Had to solve this myself today. Solved it in C# as I needed it for a program, but I guess it can be esily rewritten. Consider this Public Domain.

public static string GetGitRoot (string file_path) {

    file_path = System.IO.Path.GetDirectoryName (file_path);

    while (file_path != null) {

        if (Directory.Exists (System.IO.Path.Combine (file_path, ".git")))
            return file_path;

        file_path = Directory.GetParent (file_path).FullName;

    }

    return null;

}

참고URL : https://stackoverflow.com/questions/957928/is-there-a-way-to-get-the-git-root-directory-in-one-command

반응형