def find_lowest_common_anccestor(repository_path, branch_1, branch_2): # Go up in the hirrchy and save the commit id in a set # if it already exist in the set this is the LCA if get_commit_by_branch(branch_1) == get_commit_by_branch(branch_2): return get_commit_by_branch(branch_1) parents_cash = set() parents_to_traverse = [get_commit_by_branch(branch_1)] while len(parents_to_traverse): current_node = parents_to_traverse.pop() parents_cash.add(current_node) for parent in get_parents(repository_path, current_node): if parent != 'None': parents_to_traverse.append(parent) parents_to_traverse = [get_commit_by_branch(branch_2)] while len(parents_to_traverse): current_node = parents_to_traverse.pop() if current_node != 'None': if current_node in parents_cash: return current_node else: for parent in get_parents(repository_path, current_node): parents_to_traverse.append(parent) if parent == 'None': return None
def update_branch_if_needed(commit_id): # If the active branch is same as the head, # Update branch active_branch = get_active_branch() head = get_commit_by_branch('HEAD') if get_commit_by_branch(active_branch) == head: update_ref(active_branch, commit_id)
def status(): """This function will retrive the repository status. Usage: python path/to/wit.py status """ logger = define_logging(__name__) # Find the repository repository_path = get_wit_repo_path() head = get_commit_by_branch('HEAD') staged_files = get_staged_files(repository_path, head) not_staged_changes = list(get_unstaged_files(repository_path)) untracked_files = get_untracked_files(repository_path, staged_files) logger.info(f'HEAD: {head}') logger.info( f'Changes to be committed ({len(staged_files)}) :\n{format_list(staged_files)}' ) logger.info( f'Changes not staged for commit ({len(not_staged_changes)}) :\n{format_list(not_staged_changes)}' ) logger.info( f'Untracked files ({len(untracked_files)}) :\n{format_list(untracked_files)}' ) return
def commit(message, additional_parents=None): """ This function will copy an "image" to the IMAGES_FOLDER and will add an reference file if needed """ # Find the repository repository_path = get_wit_repo_path() # proceed only if there is staged files if len(get_staged_files(repository_path, head=get_commit_by_branch('HEAD'))) == 0: return # create image folder commit_id = generate_id() current_image_folder = Path(repository_path, IMAGES_FOLDER, commit_id) Path.mkdir(current_image_folder) # create metedata create_metadate_file(current_image_folder.parent, commit_id, message, additional_parents) # add all files add(relative_path_to_add=PurePath(REPOSITORY_FOLDER, STAGING_FOLDER), destination=current_image_folder, keep_destination=True) # update reference reference_file = Path(REPOSITORY_FOLDER, REFERENCE_FILE) if not reference_file.exists(): init_reference(reference_file, commit_id) else: update_reference(commit_id)
def checkout(commit_id_or_branch): """ This function will restore the image in the relevant commit_id folder """ # Find the repository repository_path = get_wit_repo_path() commit_id = resolve_commit_id(commit_id_or_branch) # Fail if there is staged files or track files has been changed currend_head = get_commit_by_branch('HEAD') if (len(get_staged_files(repository_path, currend_head)) or len(list(get_unstaged_files(repository_path)))): raise UncommitedChangesError() # Restore origin files to image state image_folder = Path(repository_path, IMAGES_FOLDER, commit_id) shutil.copytree(image_folder, repository_path.parent, dirs_exist_ok=True) # Restore the staging area to image state # Ignore deleted files at this point, # so all files should be in staging folder. shutil.copytree(image_folder, Path(repository_path, STAGING_FOLDER), dirs_exist_ok=True) # Update the HEAD update_ref('HEAD', commit_id) activate_branch(resolve_branch_name(commit_id_or_branch))
def graph(all_flag): repository_path = get_wit_repo_path() curent_commit = get_commit_by_branch('HEAD') g = Digraph('G', filename=str( Path(repository_path, 'wit_graph')), format='png') for branch in list(get_all_branches()): g.attr('node', shape='box', size='6,6') g.node(branch) g.attr('node', color='lightblue2', style='filled', shape='circle') g.edge(branch, break_line(get_commit_by_branch(branch))) if all_flag: draw_all_nodes(g, repository_path).view() else: draw_current_branch(g, repository_path, curent_commit).view()
def merge(destination_branch): """This function will create new commit that contains teh changes from the curent active branch and the destination branch""" repository_path = get_wit_repo_path() lca = find_lowest_common_anccestor(repository_path, 'HEAD', destination_branch) print(lca) # get changed files from lca (lowest common anccestor commit) changed = list( get_all_changed_files(repository_path, lca, get_commit_by_branch(destination_branch))) # replace the changed files into the staging area and commit them for file_ in changed: original_file = Path(repository_path, IMAGES_FOLDER, get_commit_by_branch(destination_branch), file_) destination = Path(repository_path, STAGING_FOLDER, file_) shutil.copy2(original_file, destination) commit(f"mrege: branch {get_active_branch()}", additional_parents=list(destination_branch))
def create_metadata(message, additional_parents): parents = get_commit_by_branch('HEAD') if additional_parents: parents = ",".join([str(parents)].extend([additional_parents])) return f'parent={parents}\ndate={datetime.now()}\nmessage={message}\n'
def branch(branch_name): # Find the repository get_wit_repo_path() add_ref(branch_name, get_commit_by_branch('HEAD'))
def resolve_branch_name(commit_id_or_branch): # if comit id suppordet, the branch will be None if get_commit_by_branch(commit_id_or_branch): return commit_id_or_branch return None
def resolve_commit_id(param): commit_id = get_commit_by_branch(param) if commit_id is not None: return commit_id else: return param