-->

How to figure out a working copy contains a subtre

2019-05-08 06:50发布

问题:

let's assume we've the following working copy structure:

.
├── adm
└── etc

with

$ git remote -v
origin  git@github.com:xxx/my.git (fetch)
origin  git@github.com:xxx/my.git (push)

Now, let's assume we've added a sub-project via git subtree:

git remote add extlip git@github.com:yyy/ExtLib.git
git subtree add -P tech -m "added extlib as a sub-project" extlib/master

Such that

.
├── adm
├── etc
└── tech

with

$ git remote -v
origin  git@github.com:xxx/my.git (fetch)
origin  git@github.com:xxx/my.git (push)
extlip  git@github.com:yyy/ExtLib.git (fetch)
extlip  git@github.com:yyy/ExtLib.git (push)

Now assume you aren't working on this project for a while, how do you identify the root of the sub-project? Say, how do you identify the location where you "subtree-ed" and which one is the correct remote? Or, how do you identify that you "subtree-ed" at all?

回答1:

One way of detecting the commit where a subtree was added is to look for a merge commit where the two parents do not belong to the same tree, or in other words those two commits do not share any previous commit in their history.

An example script of how to detect such in bash running it from the root your git repository:

#!/bin/bash

# To separate the rev-list by newlines
IFS=$'\n'

# This rev list will return the hash and the parents, separated by spaces,
# of any merge commit found in the history of HEAD
for hashes in $(git rev-list --merges --parents HEAD); do

    # To split the commits by space
    IFS=$' '
    hashList=($hashes)

    # Merge base will find the most recent commit shared by all the
    # given commits, output dumped just to not clutter
    git merge-base ${hashList[1]} ${hashList[2]} > /dev/null

    # We care only if such commit did not exist, which means each parent is
    # in its own separate tree
    if [[ $? != 0 ]]; then
        echo "Subtree merge: ${hashList[0]}"
    fi
done
unset IFS