Example #1
0
def delete_branch(delete_branchname,force=False,remote=None, verbose=0):
    '''delete a branch.  
    if remote=True, then look in refs/remotes, otherwise check refs/heads
    for local, check if it has a remote tracking branch, and only allow delete if upstream has merged
    '''
    print 'delete',delete_branchname,force,remote
    repo=_get_repo()
    if remote:
        qualified_branch=repo._format_ref_remote(delete_branchname)
    else:
        qualified_branch=repo._format_ref_branch(delete_branchname)
        if delete_branchname == repo.active_branch:
            GitError('Cannot delete active branch.  ')


    remote_tracking_branch=get_remote_tracking_branch(repo,delete_branchname)

    if remote_tracking_branch and not force:
        #see if local is ahead of remote
        commits_ahead=count_commits_between(repo,
                                 repo.refs[qualified_branch],
                                 repo.remote_branches[remote_tracking_branch] 
                                 )[0]
        if commits_ahead:
            raise GitError('{0} is ahead of {1} by {2} commits.\nuse git branch -D\n'.format(delete_branchname,
                                    remote_tracking_branch,
                                    commits_ahead))
    print 'removing {} (was {})\n'.format(delete_branchname,repo.refs[qualified_branch])
    del repo.repo.refs[qualified_branch]

    if not remote:
        remove_tracking(delete_branchname)
Example #2
0
def delete_branch(delete_branchname, force=False, remote=None, verbose=0):
    '''delete a branch.  
    if remote=True, then look in refs/remotes, otherwise check refs/heads
    for local, check if it has a remote tracking branch, and only allow delete if upstream has merged
    '''
    print 'delete', delete_branchname, force, remote
    repo = _get_repo()
    if remote:
        qualified_branch = repo._format_ref_remote(delete_branchname)
    else:
        qualified_branch = repo._format_ref_branch(delete_branchname)
        if delete_branchname == repo.active_branch:
            GitError('Cannot delete active branch.  ')

    remote_tracking_branch = get_remote_tracking_branch(
        repo, delete_branchname)

    if remote_tracking_branch and not force:
        #see if local is ahead of remote
        commits_ahead = count_commits_between(
            repo, repo.refs[qualified_branch],
            repo.remote_branches[remote_tracking_branch])[0]
        if commits_ahead:
            raise GitError(
                '{0} is ahead of {1} by {2} commits.\nuse git branch -D\n'.
                format(delete_branchname, remote_tracking_branch,
                       commits_ahead))
    print 'removing {} (was {})\n'.format(delete_branchname,
                                          repo.refs[qualified_branch])
    del repo.repo.refs[qualified_branch]

    if not remote:
        remove_tracking(delete_branchname)
Example #3
0
def branch_list(result):
    # TODO: tracking branches
    N = result.abbrev
    repo = _get_repo()
    if not result.remotes:
        for key, value in repo.branches.iteritems():
            dispval = value[0:N]  #todo, --abbrev=n
            commitmsg = (repo[value].message if result.verbose else '').strip()
            tracking = get_remote_tracking_branch(repo, key)
            trackmsg = ''
            diffmsg = trackingsha = ''
            if tracking:
                trackingsha = repo.remote_branches[tracking]
                ahead, behind = count_commits_between(repo, value, trackingsha)
                diffmsg = '+{}/-{} compare to'.format(
                    ahead, behind) if result.verbose else ''
                trackmsg = '[{} {} {}]'.format(diffmsg, tracking,
                                               trackingsha[0:N])
            print('* ' if repo.active_branch == key else
                  '') + key, dispval, trackmsg, commitmsg
    if result.remotes or result.all:
        for key, value in repo.remote_branches.iteritems():
            dispval = value[0:N]  #todo, --abbrev=n
            commitmsg = (repo[value].message if result.verbose else '').strip()
            print('* ' if repo.active_branch == key else
                  '') + key, dispval, commitmsg
Example #4
0
def format_tracking_branch_desc(repo,branchname):
    try:
        remote=get_remote_tracking_branch(repo,branchname)
        mysha=repo.branches[branchname]
        theirsha=repo.remote_branches[remote]
        ahead,behind=count_commits_between(repo,mysha, theirsha)
        return '+{}/-{} relative to {} ({})'.format(ahead,behind,remote,theirsha)
    except KeyError:
        return ''
Example #5
0
def format_tracking_branch_desc(repo,branchname):
    try:
        remote=get_remote_tracking_branch(repo,branchname)
        mysha=repo.branches[branchname]
        theirsha=repo.remote_branches[remote]
        ahead,behind=count_commits_between(repo,mysha, theirsha)
        return '+{}/-{} relative to {} ({})'.format(ahead,behind,remote,theirsha)
    except KeyError:
        return ''
Example #6
0
def branch_list(result):
        # TODO: tracking branches
        N=result.abbrev
        repo = _get_repo()
        if not result.remotes:
            for key,value in repo.branches.iteritems():
                dispval=value[0:N]  #todo, --abbrev=n
                commitmsg=(repo[value].message if result.verbose else '').strip()
                tracking=get_remote_tracking_branch(repo,key)
                trackmsg=''
                diffmsg=trackingsha=''
                if tracking:
                    trackingsha=repo.remote_branches[tracking]
                    ahead,behind= count_commits_between(repo,value,trackingsha)
                    diffmsg='+{}/-{} compare to'.format(ahead,behind) if result.verbose else ''
                    trackmsg='[{} {} {}]'.format(diffmsg,tracking,trackingsha[0:N])
                print ('* ' if repo.active_branch == key else '') + key, dispval, trackmsg, commitmsg
        if result.remotes or result.all:
            for key, value in repo.remote_branches.iteritems():
                dispval=value[0:N]  #todo, --abbrev=n
                commitmsg=(repo[value].message if result.verbose else '').strip()
                print ('* ' if repo.active_branch == key else '') + key,  dispval, commitmsg
Example #7
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.