2016-04-13 5 views
0

В этом случае репозиторий не имеет символических ссылок, но рабочий каталог, который я просматриваю, выполнен. Зачем? У меня есть существующий репозиторий для веб-сайта. Для простоты предположим, что структура каталога для этого:Git checkout в рабочий каталог с символическими ссылками

 
bin 
www 

Но теперь, чтобы сэкономить деньги, я припаркованный этот сайт под существующей учетной записью ISP, так что WWW каталога теперь поддиректории www по названию припаркованный домен. Таким образом, фактическая структура каталогов теперь:

 
bin 
www 
    parked-domain 

Мое решением я думал создать каталог с именем WorkDir с двумя символическими ссылками именованных бин и WWW что отнесенных к бен и припаркованных -domain каталогов в предыдущей структуре каталогов. Тогда я сделал бы команду оформления заказа с --work дерева параметра, определяющим этот WorkDir каталога и надеюсь, что поскольку бен и WWW каталогов в WORKDIR уже существует, команда фотографии не воссоздавать их , Но, увы, символические ссылки удаляются и создаются регулярные каталоги. Есть ли решение этой проблемы, кроме копирования целых структур каталогов?

ответ

0

Не похоже, что это выполнимо. Что нужно: (1) Возможность проверки только одного подкаталога и (2) Возможность переопределить имя каталога, которое будет использоваться в рабочем каталоге при проверке этого подкаталога. Что-то вроде следующего:

git --work-tree=$HOME/www checkout-tree master www parked-domain 

Кстати, CVS, которые все любят стучать в эти дни, может сделать это.

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

Я создал рабочий каталог, work_dir, в рамках которого я создал символические ссылки на «реальные» каталоги , Например,

ln -s ~/www/parked-domain www 

у меня в удаленном хранилище (инициализируется с опцией --bare) создал после приема крюка. Мы знаем, что этот крючок не может использовать команду git checkout, потому что символические ссылки будут наложены. Вместо этого выполняется команда git diff, чтобы посмотреть, какие файлы были добавлены/изменены, какие файлы были удалены текущим push. Затем крючок выполняет команду удаления для каждого файла, который был указан как удаленный нажатием. Затем крючок выполняет команду git архива, чтобы сбрасывать каждый файл, который был добавлен или изменен нажатием, а затем командой tar, чтобы извлечь эти файлы в рабочий каталог.Для самого первого нажатия «от хеша ревизии» составляет 40 нулей, и в этом случае весь репозиторий сбрасывается и извлекается через git archive. Ниже приведена реализация в Python:

#!/usr/bin/env python 

import sys, os, subprocess, re, string 

SEP = os.sep 

def log(s): 
    sys.stdout.write(s); 
    sys.stdout.flush(); 

def runCmd(cmd): 
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE) 
    output = p.communicate() 
    return output[0] 


def runPipe(cmd1, cmd2): 
    p1 = subprocess.Popen(cmd1, stdout=subprocess.PIPE) 
    p2 = subprocess.Popen(cmd2, stdin=p1.stdout, stdout=subprocess.PIPE) 
    output = p2.communicate() 
    return output[0] 


def getBranch(ref, gitDir): 
    gitDirParam = '--git-dir=' + gitDir 
    return runCmd(['git', gitDirParam, 'rev-parse', '--symbolic', '--abbrev-ref', ref]).strip() 

def isRenamedDirectory(fromDir, renameDict): 
    # simple case: 
    if fromDir in renameDict: 
     return True, renameDict[fromDir] 
    fDir = fromDir.split(SEP) 
    n = len(fDir) 
    if n != 1: 
     for i in range(n - 1, 0, -1): 
      fromDirNew = SEP.join(fDir[0:i]) 
      if fromDirNew in renameDict: 
       newDir = renameDict[fromDirNew] + SEP + SEP.join(fDir[i:]) 
       renameDict[fromDir] = newDir 
       return True, newDir 
    return False, fromDir 

def process(fromCommit, toCommit, gitDir): 
    log('Processing %s - %s\n' % (fromCommit, toCommit)) 
    gitDirParam = '--git-dir=' + gitDir 
    if fromCommit == 40*'0': 
     log('"Checking out" everything.\n') 
     archiveCmd = ['git', gitDirParam, 'archive', '--format=tar.gz', toCommit] 
     tarCmd = ['tar', '--warning=no-timestamp', '-zxf', '-'] 
     out = runPipe(archiveCmd, tarCmd) 
     log(out) 
     return 

    diffs = runCmd(['git', gitDirParam, 'diff', '--name-status', '--find-renames=100', fromCommit, toCommit]).split('\n') 
    updateList = [] 
    renameDict = dict() 
    renameSet = set() 
    defferedDiffs = [] 
    for this_pass in range(1, 3): 
     for diff in diffs if this_pass == 1 else defferedDiffs: 
      m = re.match(r'^R100\t(.*)\t(.*)$', diff) 
      if m: 
       # rename: 
       fromPath = m.group(1) 
       toPath = m.group(2) 
       (fromDir, fromFilename) = os.path.split(fromPath) 
       (toDir, toFilename) = os.path.split(toPath) 
       isRenamed, newDir = isRenamedDirectory(fromDir, renameDict) 
       if isRenamed: 
        # it's been renamed to newDir 
        fromPath = newDir + SEP + fromFilename 
       elif fromDir != toDir and fromDir != '' and toDir != '' and not os.path.isdir(toDir): 
        # a directory is being renamed or moved 
        # has directory already been renamed or moved? 
        fDir = fromDir.split(SEP) 
        tDir = toDir.split(SEP) 
        l = min(len(fDir), len(tDir)) 
        i = 0; 
        fDirLast = [] 
        while i < l and fDir[-1] == tDir[-1]: 
         fDirLast.append(fDir.pop(-1)) 
         tDir.pop(-1) 
         i += 1 
        subDirOld = SEP.join(fDir) 
        subDirNew = SEP.join(tDir) 
        while subDirOld not in renameSet and os.path.isdir(subDirNew): 
         assert len(fDirLast) 
         lastDir = fDirLast.pop(-1) 
         subDirOld += SEP + lastDir 
         subDirNew += SEP + lastDir 
        if subDirOld not in renameSet: 
         log("Renaming directory %s to %s\n" % (subDirOld, subDirNew)) 
         runCmd(['mv', subDirOld, subDirNew]) 
         renameSet.add(subDirOld) 
        renameDict[fromDir] = toDir 
        # this is the name of the file in the renamed or removed path 
        fromPath = toDir + SEP + fromFilename 
        # fall through and see if filename has also changed 
       if fromPath != toPath: 
        if os.path.isdir(toDir): 
         log("Renaming file %s to %s\n" % (fromPath, toPath)) 
         runCmd(['mv', fromPath, toPath]) 
        else: 
         # we have to defer this to a second pass 
         if this_pass == 1: 
          defferedDiffs.append(diff) 
         else: 
          log("Can't rename file %s to %s -- directory %s does not exist. % (fromPath, toPath, toDir)") 
       continue 
      m = re.match(r'^([ACDMTUXB])\t(.*)$', diff) 
      if m is None: 
       continue 
      action = m.group(1) 
      path = m.group(2) 
      if action != 'D': 
       updateList.append(path) 
      else: 
       (fileDir, fileName) = os.path.split(path) 
       if fileDir != '' and fileDir in renameDict: 
        path = renameDict[fileDir] + SEP + fileName 
       if os.path.isfile(path): 
        try: 
         os.remove(path) 
        except Exception as e: 
         log('Could not delete %s: %s\n' % (path, str(e))) 
        else: 
         log('Deleted %s\n' % path) 

    if len(updateList) == 0: 
     return 
    archiveCmd = ['git', gitDirParam, 'archive', '--format=tar.gz', toCommit] 
    archiveCmd.extend(updateList); 
    tarCmd = ['tar', '--warning=no-timestamp', '-zxvf', '-'] 
    out = runPipe(archiveCmd, tarCmd) 
    log(out) 

def process_revisions(gitDir, workDir): 
    log('Using Git directory %s, work directory %s\n' % (gitDir, workDir)) 
    curDir = os.getcwd() 
    try: 
     os.chdir(workDir) 
     lines = sys.stdin.readlines() 
     for line in lines: 
      tokens = string.split(line.strip()) 
      fromCommit = tokens[0] 
      toCommit = tokens[1] 
      branch = getBranch(tokens[2], gitDir) 
      if branch != 'master': 
       log('Not on master branch -- skipping.\n') 
      else: 
       process(fromCommit, toCommit, gitDir) 
    except Exception as e: 
     log(str(e)) 
    os.chdir(curDir) 

GIT_DIR = '%s%s%s' % (os.environ['HOME'], SEP, 'repository.git') 
WORK_DIR = '%s%s%s' % (os.environ['HOME'], SEP, 'work_dir') 
process_revisions(GIT_DIR, WORK_DIR)