예제 #1
0
def create_branch(new_branch, base_rev, force=False ,no_track=False  ):
        """Try creating a new branch which tracks the given remote
            if such a branch does not exist then branch off a local branch
        """
        repo=_get_repo()
        
        # Already exists
        if new_branch in repo.branches:
            if not force:
                raise GitError("branch %s already exists\n use --force to overwrite anyway" % new_branch)
       
         # fork with new sha
        new_ref = repo._format_ref_branch(new_branch)
        base_sha=find_revision_sha(repo,base_rev)
        repo.repo.refs[new_ref] = base_sha
        
        #handle tracking, only if this was a remote
        tracking,remote_branch =( ['origin']+base_rev.split('/'))[-2:]  #branch-> origin/branch.  remote/branch stays as is
        qualified_remote_branch=os.path.sep.join([tracking,remote_branch])
        if qualified_remote_branch in repo.remote_branches and not base_rev in repo.branches:
            if not no_track:
                add_tracking(new_branch,tracking,remote_branch)
            else:
                remove_tracking(new_branch)

        #todo reflog
        return new_ref
예제 #2
0
def create_branch(new_branch, base_rev, force=False, no_track=False):
    """Try creating a new branch which tracks the given remote
            if such a branch does not exist then branch off a local branch
        """
    repo = _get_repo()

    # Already exists
    if new_branch in repo.branches:
        if not force:
            raise GitError(
                "branch %s already exists\n use --force to overwrite anyway" %
                new_branch)

    # fork with new sha
    new_ref = repo._format_ref_branch(new_branch)
    base_sha = find_revision_sha(repo, base_rev)
    repo.repo.refs[new_ref] = base_sha

    #handle tracking, only if this was a remote
    tracking, remote_branch = (['origin'] + base_rev.split('/'))[
        -2:]  #branch-> origin/branch.  remote/branch stays as is
    qualified_remote_branch = os.path.sep.join([tracking, remote_branch])
    if qualified_remote_branch in repo.remote_branches and not base_rev in repo.branches:
        if not no_track:
            add_tracking(new_branch, tracking, remote_branch)
        else:
            remove_tracking(new_branch)

    #todo reflog
    return new_ref
예제 #3
0
def merge(args):
    helptext='''git merge' [--msg <msg>] [<commit>]
    git merge --abort\n
    
    merges <commit> into HEAD, or remote tracking branch if commit not specified.
    <commit> can be a local or remote ref, or an existing commit sha.

    merge will handle unambiguous conflicts between head and other 
    merge head, and will insert conflict markers if conflicts cannot be resolved.  
    note that the strategy used will prefer changes in the local head.  
    for instance, if HEAD deleted a section, while MERGE_HEAD modified the same 
    action, the section will be deleted from the final without indicating a conflict.
      
    be sure to commit any local changes before running merge, as files in working tree (i.e on disk) are changed, and checked in, which will probably overwrite any local uncomitted changes.
    
    note merge will not actually commit anything.  run git commit to commit a successful merge.

    
    --abort will remove the MERGE_HEAD and MERGE_MSG files, and will reset staging area, but wont affect files on disk.  use git reset --hard or git checkout if this is desired.
    '''
    repo=_get_repo()
    print '_'*30

    parser=argparse.ArgumentParser(prog='merge', usage=helptext)
    parser.add_argument('commit',action='store',nargs='?', help='commit sha, local branch, or remote branch name to merge from')
    parser.add_argument('--msg',nargs=1,action='store',help='commit message to store')
    parser.add_argument('--abort',action='store_true',help='abort in progress merge attempt')
    result=parser.parse_args(args)
    
    if result.abort:
        print 'attempting to undo merge.  beware, files in working tree are not touched.  \nused git reset --hard to revert particular files'
        git_reset([])
        os.remove(os.path.join(repo.repo.controldir(),'MERGE_HEAD'))
        os.remove(os.path.join(repo.repo.controldir(),'MERGE_MSG'))

    #todo: check for uncommitted changes and confirm
    
    # first, determine merge head
    merge_head = find_revision_sha(repo,result.commit or get_remote_tracking_branch(repo,repo.active_branch))
    if not merge_head:
        raise GitError('must specify a commit sha, branch, remote tracking branch to merge from.  or, need to set-upstream branch using git branch --set-upstream <remote>[/<branch>]')

    head=find_revision_sha(repo,repo.active_branch)

    base_sha=merge_base(repo,head,merge_head)[0]  #fixme, what if multiple bases

    if base_sha==head:
        print 'Fast forwarding {} to {}'.format(repo.active_branch,merge_head)
        repo.refs['HEAD']=merge_head
        return 
    if base_sha == merge_head:
        print 'head is already up to date'
        return  
    
    print 'merging <{}> into <{}>\n{} commits ahead of merge base <{}> respectively'.format(merge_head[0:7],head[0:7],count_commits_between(repo,merge_head,head),base_sha[0:7])
    base_tree=repo[base_sha].tree
    merge_head_tree=repo[merge_head].tree
    head_tree=repo[head].tree

    num_conflicts,added,removed=merge_trees(repo.repo.object_store, base_tree,head_tree,merge_head_tree)
    # update index
    if added: 
        porcelain.add(repo.path, added)
    if removed: 
        porcelain.rm(repo.path, removed)

    repo.repo._put_named_file('MERGE_HEAD',merge_head)
    repo.repo._put_named_file('MERGE_MSG','Merged from {}({})'.format(merge_head, result.commit))
    print 'Merge complete with {} conflicted files'.format(num_conflicts)
    print '''Merged files were added to the staging area, but have not yet been comitted.