def checkout(remoteBranch, localBranch, tag): repo = Repo('.') print('Fetching ' + remoteBranch) if tag: Remote(repo, 'upstream').fetch('refs/tags/' + remoteBranch) else: Remote(repo, 'upstream').fetch(remoteBranch) print('Creating and checking out ' + localBranch) repo.create_head(localBranch, 'FETCH_HEAD').checkout()
def checkout_branch(repo, branch_name, no_pull=False): """Checkout a branch and optionally pull updates. :param repo: Repo object :param branch_name: Name of the branch to checkout :param no_pull: (Default: False) If True, don't pull changes to branch :return: Head object for the checked out branch """ base_head = Head(repo, f'refs/heads/{branch_name}') if repo.active_branch != base_head: print(f'Checking out {branch_name}.') base_head.checkout() if not no_pull and base_head.tracking_branch(): print(f'Pulling updates to {branch_name}...') remote_name = base_head.tracking_branch().remote_name remote = Remote(repo, remote_name) base_commit = base_head.commit for fetch_info in remote.pull(): if fetch_info.ref == base_head.tracking_branch(): if fetch_info.commit != base_commit: print( f'Updated {branch_name} to {fetch_info.commit.hexsha}') else: print(f'{branch_name} already up to date.') print('') return base_head
name = input(name_query) while not name: name = input(name_query) confirm_query = "Is this information correct? \n" + "Remote url: " + remote_url + "\n" + "Project name: " + name + "\n" + "(Y/N): " confirm_response = input(confirm_query).lower() while confirm_response != "y" and confirm_response != "n": confirm_response = input(confirm_query).lower() if confirm_response == "n": continue else: break # Set remote url remote = Remote(repo, "origin") remote.set_url(remote_url) # Pull submodules for submodule in repo.submodules: submodule.update(init=True) # Set project name: name = "_".join(name.split()) cmake_lists = "CMakeLists.txt" with open(cmake_lists) as f: s = f.read() with open(cmake_lists, "w") as f: replaced = s.replace("vulkan_project", name) f.write(replaced)
def git_check(wdir='.'): git_root = git_rootdir(wdir) if git_root == None: return 0 f = "{}/.git/FETCH_HEAD".format(os.path.abspath(git_root)) if os.path.isfile(f): ''' make sure this is not a freshly cloned repo with no FETCH_HEAD ''' last_fetch = int(os.stat(f).st_mtime) diff = int(time.time() - last_fetch) else: # if the repo is a fresh clone, there is no FETCH_HEAD # so set time diff to more than a minute to force a fetch diff = 61 repo = Repo(git_root) assert not repo.bare remote_names = [] # fetch at most once per minute for r in repo.remotes: remote_names.append(r.name) if diff > 60: remote = Remote(repo, r.name) remote.fetch() # check what branch we're on branch = repo.active_branch.name origin_branch = None for ref in repo.git.branch('-r').split('\n'): for rn in remote_names: if "{}/{}".format(rn, branch) in ref: origin_branch = ref.strip() break if origin_branch == None: # no remote branch to compare to return 0 # check if local branch is ahead and /or behind remote branch command = "git -C {} rev-list --left-right --count \"{}...{}\"".format( git_root, branch, origin_branch) #print command (ahead_behind, err, exitcode) = run(command, raise_exception_on_fail=True) ahead_behind = ahead_behind.strip().split("\t") ahead = int(ahead_behind[0]) behind = int(ahead_behind.pop()) if behind > 0: sys.stderr.write("") sys.stderr.write( "GIT ERROR: You are on branch {} and are behind the remote. Please git pull and/or merge before proceeding. Below is a git status:" .format(branch)) sys.stderr.write("") (status, err, exitcode) = run("git -C {} status ".format(git_root)) sys.stderr.write(status) sys.stderr.write("") return (-1) else: TB_GIT_DEFAULT_BRANCH = os.getenv('TB_GIT_DEFAULT_BRANCH', 'master') if branch != TB_GIT_DEFAULT_BRANCH: ''' in this case assume we're on a feature branch if the FB is behind master then issue a warning ''' command = "git -C {} branch -vv | grep {} ".format( git_root, TB_GIT_DEFAULT_BRANCH) (origin_master, err, exitcode) = run(command) if exitcode != 0: ''' In this case the git repo does not contain TB_GIT_DEFAULT_BRANCH, so I guess assume that we're on the default branch afterall and that we're up to date persuant to the above code ''' return 0 for line in origin_master.split("\n"): if line.strip().startswith(TB_GIT_DEFAULT_BRANCH): origin = line.strip().split('[')[1].split('/')[0] assert origin != None command = "git -C {} rev-list --left-right --count \"{}...{}/{}\"".format( git_root, branch, origin, TB_GIT_DEFAULT_BRANCH) (ahead_behind, err, exitcode) = run(command) ahead_behind = ahead_behind.strip().split("\t") ahead = int(ahead_behind[0]) behind = int(ahead_behind.pop()) command = "git -C {} rev-list --left-right --count \"{}...{}\"".format( git_root, branch, TB_GIT_DEFAULT_BRANCH) (ahead_behind, err, exitcode) = run(command) ahead_behind = ahead_behind.strip().split("\t") local_ahead = int(ahead_behind[0]) local_behind = int(ahead_behind.pop()) if behind > 0: sys.stderr.write("") sys.stderr.write( "GIT WARNING: Your branch, {}, is {} commit(s) behind {}/{}.\n" .format(branch, behind, origin, TB_GIT_DEFAULT_BRANCH)) sys.stderr.write( "This action may clobber new changes that have occurred in {} since your branch was made.\n" .format(TB_GIT_DEFAULT_BRANCH)) sys.stderr.write( "It is recommended that you stop now and merge or rebase from {}\n" .format(TB_GIT_DEFAULT_BRANCH)) sys.stderr.write("\n") if ahead != local_ahead or behind != local_behind: sys.stderr.write("") sys.stderr.write( "INFO: your local {} branch is not up to date with {}/{}\n" .format(TB_GIT_DEFAULT_BRANCH, origin, TB_GIT_DEFAULT_BRANCH)) sys.stderr.write("HINT:") sys.stderr.write( "git checkout {} ; git pull ; git checkout {}\n". format(TB_GIT_DEFAULT_BRANCH, branch)) sys.stderr.write("\n") answer = raw_input( "Do you want to continue anyway? [y/N]? ").lower() if answer != 'y': log("") log("Aborting due to user input") exit() return 0
def main(): """Entrypoint to 'gitsync' command-line tool """ parser = argparse.ArgumentParser( description='File-sync integrated with Git system solution tool') parser.add_argument('-d', '--debug', action='store_true', default=False, help='show more message for debugging') parser.add_argument( '--config_file', help= 'Specify the location of the settings (Default value: settings.json)', type=str, default=os.path.join(os.getcwd(), 'settings.json')) parser.add_argument('--init', help='Create a template configuration file', action='store_true', default=False) parser.add_argument('--version', help='Print the GitSync version number', action='version', version=__version__) # Read a set of arguments args = parser.parse_args() DEBUG = args.debug CONFIG_FILE = args.config_file INIT = args.init # Set Logging Level if DEBUG: for handler in logging.root.handlers[:]: logging.root.removeHandler(handler) logging.basicConfig(level=logging.DEBUG, format=FORMAT) logger.debug('Config file: {0}'.format(CONFIG_FILE)) if INIT: logger.info('Generate a template setting.json') with open('settings_default.json', 'w') as f: f.writelines(json.dumps(DEFAULT_SETTING, indent=4)) sys.exit() # Load config try: logger.debug('Load config...') config = load_config(CONFIG_FILE) repo_dir = config['repo_dir'] files_mapping = config['files'] dirs_mapping = config['dirs'] ignore_files = config['ignore']['patterns'] ignore_files.extend(IGNORE_PATTERNS) ignore_files = sorted(list(set(ignore_files))) except Exception as error: logger.error('Can\'t load config: {0}'.format(error)) sys.exit(1) # Read and check repo has been initialized logger.debug('Trying to read repo...') try: repo = Repo(repo_dir) remote = Remote(repo, 'origin') if not remote.exists(): logger.error( 'Can\'t find \'origin\' remote url. Please set a \'origin\' remote and upstream branch at first to proceed!' ) sys.exit(1) logger.debug('Repo has been loaded successfully') logger.info('Pulling from repo...') remote.pull() except InvalidGitRepositoryError as error: logger.error('Invalid repo. Please check it again!') sys.exit(1) except NoSuchPathError as error: logger.error( 'No directory \'.git\' found. Did you initialize git project?!') sys.exit(1) if repo.bare: logger.error('Repo can\'t be a bare!') sys.exit(1) # initialize runtime files/variables init_files(repo_dir, ignore_files) changed = False logger.info('Repo Initialization completed') logger.debug('Performing prechecks...') try: precheck(files_mapping.keys(), dirs_mapping.keys()) except Exception as error: logger.error('Prechecks failed!') logger.error(error) sys.exit(1) logger.debug('Perform cleanup task on repo...') clean_up_repo(files_mapping.values(), dirs_mapping.values(), repo_dir, ignore=ignore_files) logger.debug('Proceed to check file changes') logger.debug('Detect if the sync list changes...') prev_config = NO_LAST_SYNC_STATE if check_last_sync(repo_dir): logger.debug('Last sync record found!') prev_config = load_last_sync(repo_dir) # Check whether folder states are identical logger.info('Check files whether if updated') src_files_to_be_copied, src_dirs_to_be_copied, dst_files_to_be_deleted, dst_dirs_to_be_deleted = check_sync_state( prev_config, config, repo_dir) logger.debug( 'Sync state: \n\t\tFiles be copied {0}\n\t\tDirs be copied {1}\n\t\tFiles be deleted {2}\n\t\tDirs be deleted {3}' .format(src_files_to_be_copied, src_dirs_to_be_copied, dst_files_to_be_deleted, dst_dirs_to_be_deleted)) # Start to perform sync task (overwrite dst-file / delete dst-file / copy entire src-folder(src-file) to dst-folder(dst-file)) change_indicator = 0 if (dst_files_to_be_deleted): for file_path in dst_files_to_be_deleted: try: logger.debug('Deleting file {0}'.format(file_path)) delete_file(file_path) logger.debug(' ... Successfully') except Exception as error: logger.debug(' ... Failed') raise error logger.debug('Files deletion finished') change_indicator += 1 if (dst_dirs_to_be_deleted): for dir_path in dst_dirs_to_be_deleted: try: logger.debug('Deleting directory {0}'.format(dir_path)) delete_dir(dir_path) logger.debug(' ... Successfully') except Exception as error: logger.debug(' ... Failed') raise error logger.debug('Dirs deletion finished') change_indicator += 1 if (src_files_to_be_copied): for src_path, dst_path in src_files_to_be_copied.items(): try: logger.debug('Copying file {0} to {1}'.format( src_path, dst_path)) copy_file(src_path, dst_path) logger.debug(' ... Successfully') except Exception as error: logger.debug(' ... Failed') raise error logger.debug('Files addition finished') change_indicator += 1 if (src_dirs_to_be_copied): for src_path, dst_path in src_dirs_to_be_copied.items(): try: logger.debug('Copying directory {0} to {1}'.format( src_path, dst_path)) copy_dir(src_path, dst_path, ignore=ignore_files) logger.debug(' ... Successfully') except Exception as error: logger.debug(' ... Failed') raise error logger.debug('Dirs addition finished') change_indicator += 1 if change_indicator == 0: logger.info('All is up to date') sys.exit(0) logger.debug('Staging files...') logger.debug('Reset current staging') repo.index.reset() logger.info('Stage modified files into repo...') repo.git.add(A=True) logger.info('Commit to repo...') repo.index.commit('[(auto-git) leave it here for later editing]') logger.info('Push to remote origin server...') remote.push() logger.debug('Saving current sync state...') try: save_current_sync(repo_dir, config) except Exception as error: logger.error('Failed to save current sync state! {0}'.format(error)) sys.exit(1) logger.info('Finished')