def _clone_missing(self, git_project, repo): """ Clone Missing """ branch = repo.default_branch fixed_ref = repo.fixed_ref clone_url = repo.clone_url qisys.sh.mkdir(git_project.path, recursive=True) git = qisrc.git.Git(git_project.path) remote_name = repo.default_remote.name try: git.init() git.remote("add", remote_name, clone_url) git.fetch(remote_name, "--quiet") if branch: git.checkout("-b", branch, "%s/%s" % (remote_name, branch)) if fixed_ref: git.checkout("-q", fixed_ref) except Exception: ui.error("Cloning repo failed") if git.is_empty(): qisys.sh.rm(git_project.path) self.worktree.remove_project(repo.src) return False self.save_project_config(git_project) self.load_git_projects() return True
def _test_switching_to_fixed_ref_happy(qisrc_action, git_server, record_messages, tag_ref_to_test, branch_ref_to_test): git_server.create_repo("foo.git") git_server.push_file("foo.git", "a.txt", "a") git_server.push_tag("foo.git", "v0.1") git_server.push_file("foo.git", "b.txt", "b") git_server.push_branch("foo.git", "feature/b") git_server.push_file("foo.git", "c.txt", "c") qisrc_action("init", git_server.manifest_url) # Check for fixed_ref tag git_server.set_fixed_ref("foo.git", tag_ref_to_test) qisrc_action("sync") git_worktree = TestGitWorkTree() foo_proj = git_worktree.get_git_project("foo") git = qisrc.git.Git(foo_proj.path) _, sha1 = git.call("rev-parse", "HEAD", raises=False) expected = git.get_ref_sha1("refs/tags/v0.1") assert sha1 == expected # qisrc.reset.clever_reset_ref should tell where is the HEAD after reset record_messages.reset() qisrc_action("sync") assert record_messages.find("HEAD is now at") assert record_messages.find("Add a.txt") _, status_output = git.status(raises=False) assert "HEAD" in status_output assert "detached" in status_output # If branch ref name is local, makesure it exists on local copy, then go back to master if branch_ref_to_test == "feature/b": git.checkout("feature/b", raises=False) git.checkout("master", raises=False) # Check for fixed_ref branch git_server.set_fixed_ref("foo.git", branch_ref_to_test) qisrc_action("sync") git_worktree = TestGitWorkTree() foo_proj = git_worktree.get_git_project("foo") git = qisrc.git.Git(foo_proj.path) _, sha1 = git.call("rev-parse", "HEAD", raises=False) expected = git.get_ref_sha1("refs/remotes/origin/feature/b") assert sha1 == expected # qisrc.reset.clever_reset_ref should tell where is the HEAD after reset record_messages.reset() qisrc_action("sync") assert record_messages.find("HEAD is now at") assert record_messages.find("Add b.txt") _, status_output = git.status(raises=False) # FIXME: when using ref long name branch (refs/xxx), if we come from a tag, we stay in a detached head, # and we should be in an attached head state to be consistent with the ref short name branc behaviour # That's not an issue for now as users reference short name in manifest, but it will be cleaner to be consistent... if not branch_ref_to_test.startswith("refs/"): assert "HEAD" not in status_output assert "detached" not in status_output else: # Remove these assert when dealing with behaviour consistency mentionned above assert "HEAD" in status_output assert "detached" in status_output
def push_file(self, project, filename, contents, branch="master", fast_forward=True, message=None): """ Push a new file with the given contents to the given project It is assumed that the project has been created """ src = project.replace(".git", "") repo_src = self.src.join(src) git = qisrc.git.Git(repo_src.strpath) if git.get_current_branch() != branch: git.checkout("--force", "-B", branch) if not fast_forward: git.reset("--hard", "HEAD~1") to_write = repo_src.join(filename) if not message: if to_write.check(file=True): message = "Update %s" % filename else: message = "Add %s" % filename repo_src.ensure(filename, file=True) repo_src.join(filename).write(contents) git.add(filename) git.commit("--message", message) if fast_forward: git.push("origin", "%s:%s" % (branch, branch)) else: git.push("origin", "--force", "%s:%s" % (branch, branch))
def push_file(self, project, filename, contents, branch="master", fast_forward=True, message=None): """ Push a new file with the given contents to the given project It is assumed that the project has beed created """ src = project.replace(".git", "") repo_src = self.src.join(src) git = qisrc.git.Git(repo_src.strpath) if git.get_current_branch() != branch: git.checkout("--force", "-B", branch) if not fast_forward: git.reset("--hard", "HEAD~1") to_write = repo_src.join(filename) if not message: if to_write.check(file=True): message = "Update %s" % filename else: message = "Add %s" % filename repo_src.ensure(filename, file=True) repo_src.join(filename).write(contents) git.add(filename) git.commit("--message", message) if fast_forward: git.push("origin", "%s:%s" % (branch, branch)) else: git.push("origin", "--force", "%s:%s" % (branch, branch))
def create_git_repo(tmp, path, with_release_branch=False): """ Create a empty git repository, which just what is enough so that it is possible to clone it Return a valid git url. """ tmp_srv = os.path.join(tmp, "srv", path + ".git") qibuild.sh.mkdir(tmp_srv, recursive=True) srv_git = qisrc.git.Git(tmp_srv) srv_git.call("init", "--bare") tmp_src = os.path.join(tmp, "src", path) qibuild.sh.mkdir(tmp_src, recursive=True) write_readme(tmp_src, path + "\n") git = qisrc.git.Git(tmp_src) git.call("init") git.call("add", ".") git.call("commit", "-m", "intial commit") git.call("push", tmp_srv, "master:master") if not with_release_branch: return tmp_srv git.checkout("-b", "release-1.12") write_readme(tmp_src, "%s on release-1.12\n" % path) git.call("add", "README") git.call("commit", "-m", "update README for 1.12") git.call("push", tmp_srv, "release-1.12:release-1.12") return tmp_srv
def test_wrong_branch_unstaged(self): bar_url = create_git_repo(self.tmp, "bar") work = os.path.join(self.tmp, "work") qibuild.sh.mkdir(work) bar_src = os.path.join(work, "bar") git = qisrc.git.Git(bar_src) git.clone(bar_url) # Checkout a 'next' branch with unstaged changes git.checkout("-b", "next") write_readme(bar_src, "bar on next\n") push_readme_v2(self.tmp, "bar", "master") err = git.update_branch("master", "origin") self.assertFalse(err) # Check we are still on next with our # unstaged changes back self.assertEqual(git.get_current_branch(), "next") readme = read_readme(bar_src) self.assertEqual(readme, "bar on next\n") # Check that master is up to date git.checkout("-f", "master") readme = read_readme(bar_src) self.assertEqual(readme, "bar v2 on master\n")
def push_submodule(self, project, submodule_url, destination_dir, branch="master", fast_forward=True, message=None): """ Push a submodule to the given project. It is assumed that the project has been created. """ src = project.replace(".git", "") repo_src = self.src.join(src) git = qisrc.git.Git(repo_src.strpath) if git.get_current_branch() != branch: git.checkout("--force", "-B", branch) if not fast_forward: git.reset("--hard", "HEAD~1") to_write = repo_src.join(destination_dir) if to_write.exists(): raise RuntimeError("path %s already exists" % destination_dir) if not message: message = "Add submodule %s" % destination_dir git.call("submodule", "add", submodule_url, destination_dir) git.add(destination_dir) git.commit("--message", message) if fast_forward: git.push("origin", "%s:%s" % (branch, branch)) else: git.push("origin", "--force", "%s:%s" % (branch, branch))
def test_wrong_branch(self): bar_url = create_git_repo(self.tmp, "bar") work = os.path.join(self.tmp, "work") qibuild.sh.mkdir(work) bar_src = os.path.join(work, "bar") git = qisrc.git.Git(bar_src) git.clone(bar_url) git.update_branch("master", "origin") readme = read_readme(bar_src) self.assertEqual(readme, "bar\n") # Checkout a 'next' branch git.checkout("-b", "next") with open(os.path.join(bar_src, "README"), "w") as fp: fp.write("bar on next\n") git.commit("-a", "-m", "README next") # Push a new commit push_readme_v2(self.tmp, "bar", "master") # Update, check that master is up to date err = git.update_branch("master", "origin") self.assertFalse(err) git.checkout("master") readme = read_readme(bar_src) self.assertEqual(readme, "bar v2 on master\n")
def fetch_manifest(worktree, manifest_git_url, branch="master", profile="default", src="manifest/default"): """ Fetch the manifest for a worktree :param manifest_git_url: A git repository containing a 'manifest.xml' file, ala repo :param branch: The branch to use :param src: The path where to store the clone of the manifest Note: every changes made by the user directly in the manifest repo will be lost! """ manifest = worktree.get_project(src) if not manifest: clone_project(worktree, manifest_git_url, src=src) manifest = worktree.get_project(src) # Make sure manifest project is on the correct, up to date branch: git = qisrc.git.Git(manifest.path) git.set_remote("origin", manifest_git_url) git.set_tracking_branch(branch, "origin") git.checkout("-f", branch, quiet=True) git.fetch(quiet=True) git.reset("--hard", "origin/%s" % branch, quiet=True) filename = profile + ".xml" manifest_file = os.path.join(manifest.path, filename) if not os.path.exists(manifest_file): mess = "Could not find a file named '%s' " % filename mess += "in the repository: %s\n" % manifest_git_url raise Exception(mess) return manifest_file
def test_fake_git_wrong_setup(): git = FakeGit("repo") git.add_result("checkout", 0, "") git.checkout("-f", "master") # pylint: disable-msg=E1101 with pytest.raises(Exception) as e: git.fetch() assert "Unexpected call to fetch" in e.value.args[0]
def test_wrong_setup(): git = FakeGit("repo") git.add_result("checkout", 0, "") git.checkout("-f", "master") # pylint: disable-msg=E1101 with pytest.raises(Exception) as e: git.fetch() assert "Unexpected call to fetch" in e.value.message
def test_retcode_when_skipping(qisrc_action, git_server): git_server.create_repo("bar") qisrc_action("init", git_server.manifest_url) git_worktree = TestGitWorkTree() bar_proj = git_worktree.get_git_project("bar") git = TestGit(bar_proj.path) git.checkout("-b", "devel") rc = qisrc_action("sync", retcode=True) assert rc != 0
def test_fake_git_configured_but_not_called(): git = FakeGit("repo") git.add_result("checkout", 1, "") git.add_result("reset", 0, "") # pylint: disable-msg=E1101 git.checkout(raises=False) with pytest.raises(Exception) as e: git.check() assert "reset was added as result but never called" in e.value.args[0]
def test_configured_but_not_called(): git = FakeGit("repo") git.add_result("checkout", 1, "") git.add_result("reset", 0, "") # pylint: disable-msg=E1101 git.checkout(raises=False) with pytest.raises(Exception) as e: git.check() assert "reset was added as result but never called" in e.value.message
def test_fake_git_configured_but_not_called_enough(): git = FakeGit("repo") git.add_result("checkout", 0, "") git.add_result("checkout", 1, "Unstaged changes") git.checkout("next") # pylint: disable-msg=E1101 with pytest.raises(Exception) as e: git.check() assert "checkout was configured to be called 2 times" in e.value.args[0] assert "was only called 1 times" in e.value.args[0]
def push_manifest(self, message, allow_empty=False): """ Push new manifest.xml version """ manifest_repo = self.root.join("src", "manifest") git = qisrc.git.Git(manifest_repo.strpath) commit_args = ["--all", "--message", message] if allow_empty: commit_args.append("--allow-empty") git.commit(*commit_args) git.checkout("--force", "-B", self.manifest_branch) git.push("origin", "%s:%s" % (self.manifest_branch, self.manifest_branch))
def test_configured_but_not_called_enough(): git = FakeGit("repo") git.add_result("checkout", 0, "") git.add_result("checkout", 1, "Unstaged changes") git.checkout("next") # pylint: disable-msg=E1101 with pytest.raises(Exception) as e: git.check() assert "checkout was configured to be called 2 times" in e.value.message assert "was only called 1 times" in e.value.message
def _test_switching_to_fixed_ref_happy(qisrc_action, git_server, record_messages, tag_ref_to_test, branch_ref_to_test): """ Test Switching To Fixed Ref Happy """ git_server.create_repo("foo.git") git_server.push_file("foo.git", "a.txt", "a") git_server.push_tag("foo.git", "v0.1") git_server.push_file("foo.git", "b.txt", "b") git_server.push_branch("foo.git", "feature/b") git_server.push_file("foo.git", "c.txt", "c") qisrc_action("init", git_server.manifest_url) # Check for fixed_ref tag git_server.set_fixed_ref("foo.git", tag_ref_to_test) qisrc_action("sync") git_worktree = TestGitWorkTree() foo_proj = git_worktree.get_git_project("foo") git = qisrc.git.Git(foo_proj.path) _, sha1 = git.call("rev-parse", "HEAD", raises=False) expected = git.get_ref_sha1("refs/tags/v0.1") assert sha1 == expected # qisrc.reset.clever_reset_ref should tell where is the HEAD after reset record_messages.reset() qisrc_action("sync") assert record_messages.find("HEAD is now at") assert record_messages.find("Add a.txt") _, status_output = git.status(raises=False) assert "HEAD" in status_output assert "detached" in status_output # If branch ref name is local, makesure it exists on local copy, then go back to master if branch_ref_to_test == "feature/b": git.checkout("feature/b", raises=False) git.checkout("master", raises=False) # Check for fixed_ref branch git_server.set_fixed_ref("foo.git", branch_ref_to_test) qisrc_action("sync") git_worktree = TestGitWorkTree() foo_proj = git_worktree.get_git_project("foo") git = qisrc.git.Git(foo_proj.path) _, sha1 = git.call("rev-parse", "HEAD", raises=False) expected = git.get_ref_sha1("refs/remotes/origin/feature/b") assert sha1 == expected # qisrc.reset.clever_reset_ref should tell where is the HEAD after reset record_messages.reset() qisrc_action("sync") assert record_messages.find("HEAD is now at") assert record_messages.find("Add b.txt") _, status_output = git.status(raises=False) # FIXME: when using ref long name branch (refs/xxx), if we come from a tag, we stay in a detached head, # and we should be in an attached head state to be consistent with the ref short name branc behaviour # That's not an issue for now as users reference short name in manifest, but it will be cleaner to be consistent... if not branch_ref_to_test.startswith("refs/"): assert "HEAD" not in status_output assert "detached" not in status_output else: # Remove these assert when dealing with behaviour consistency mentionned above assert "HEAD" in status_output assert "detached" in status_output
def do(args): """Main entry points.""" git_worktree = qisrc.parsers.get_git_worktree(args) snapshot = None if args.snapshot: snapshot = qisrc.snapshot.Snapshot() snapshot.load(args.snapshot) if snapshot and snapshot.format_version and snapshot.format_version >= 1: reset_manifest(git_worktree, snapshot, groups=args.groups) git_projects = qisrc.parsers.get_git_projects(git_worktree, args, default_all=True, use_build_deps=True) errors = list() for i, git_project in enumerate(git_projects): ui.info_count(i, len(git_projects), "Reset", git_project.src) src = git_project.src git = qisrc.git.Git(git_project.path) ok, message = git.require_clean_worktree() if not ok and not args.force: ui.warning(message) errors.append(src) continue git.checkout(".") if not git_project.default_branch: ui.warning(git_project.src, "not in any manifest, skipping") continue branch = git_project.default_branch.name remote = git_project.default_remote.name git.safe_checkout(branch, remote, force=True) to_reset = None if args.snapshot: to_reset = snapshot.refs.get(src) if not to_reset: ui.warning(src, "not found in the snapshot") continue elif args.tag: to_reset = args.tag else: to_reset = "%s/%s" % (remote, branch) try: qisrc.reset.clever_reset_ref(git_project, to_reset) except: errors.append(src) if not errors: return ui.error("Failed to reset some projects") for error in errors: ui.info(ui.red, " * ", error) sys.exit(1)
def change_branch(self, project, new_branch): repo = self.get_repo(project) repo_src = self.src.join(repo.src) git = qisrc.git.Git(repo_src.strpath) git.checkout("--force", "-B", new_branch) for remote in repo.remotes: git.push(remote.url, "%s:%s" % (new_branch, new_branch)) repo.default_branch = new_branch self.manifest.dump() self.push_manifest("%s on %s" % (repo.project, new_branch)) self.manifest.load()
def push_manifest(self, message, allow_empty=False): """ Push new manifest.xml version """ manifest_repo = self.root.join("src", "manifest") git = qisrc.git.Git(manifest_repo.strpath) commit_args = ["--all", "--message", message] if allow_empty: commit_args.append("--allow-empty") git.commit(*commit_args) if git.get_current_branch() != self.manifest_branch: git.checkout("--force", "-B", self.manifest_branch) git.push("origin", "%s:%s" % (self.manifest_branch, self.manifest_branch))
def test_using_force_when_not_an_a_branch(qisrc_action, git_server): git_server.create_repo("foo.git") git_server.push_file("foo.git", "foo.txt", "this is foo") manifest_url = git_server.manifest_url qisrc_action("init", manifest_url) git_worktree = TestGitWorkTree() foo_proj = git_worktree.get_git_project("foo") git = qisrc.git.Git(foo_proj.path) git.checkout("HEAD~1") assert not git.get_current_branch() qisrc_action("checkout", "master", "--force") assert git.get_current_branch() == "master"
def _sync_manifest(self, local_manifest): """ Update the local manifest clone with the remote """ manifest_repo = os.path.join(self.manifests_root, local_manifest.name) git = qisrc.git.Git(manifest_repo) with git.transaction() as transaction: git.fetch("origin") git.checkout("-B", local_manifest.branch) git.reset("--hard", "origin/%s" % local_manifest.branch) if not transaction.ok: ui.warning("Update failed") ui.info(transaction.output) return
def test_git_get_local_branches(tmpdir): tmpdir = tmpdir.strpath git = qisrc.git.Git(tmpdir) # pylint: disable-msg=E1101 with pytest.raises(Exception): git.get_local_branches() write_readme(tmpdir, "readme\n") git.call("init") git.call("add", ".") git.commit("-m", "initial commit") assert git.get_local_branches() == ["master"] git.checkout("-b", "devel") assert git.get_local_branches() == ["devel", "master"]
def test_get_current_branch(self): bar_url = create_git_repo(self.tmp, "bar") work = os.path.join(self.tmp, "work") qibuild.sh.mkdir(work) bar_src = os.path.join(work, "bar") git = qisrc.git.Git(bar_src) git.clone(bar_url) self.assertEqual(git.get_current_branch(), "master") push_readme_v2(self.tmp, "bar", "master") git.pull() self.assertEqual(git.get_current_branch(), "master") git.checkout("-f", "HEAD~1") self.assertEqual(git.get_current_branch(), None)
def test_changing_branch_of_repo_under_code_review(qisrc_action, git_server, record_messages): git_server.create_repo("foo.git", review=True) qisrc_action("init", git_server.manifest_url) git_server.change_branch("foo.git", "devel") git_worktree = TestGitWorkTree() foo_proj = git_worktree.get_git_project("foo") git = TestGit(foo_proj.path) git.checkout("-b", "devel") record_messages.reset() qisrc_action("sync") assert record_messages.find("default branch changed") assert not record_messages.find("now using code review")
def _sync_git(repo, url, branch, ref): git = qisrc.git.Git(repo) git.set_remote("origin", url) if git.get_current_branch() != branch: git.checkout("-B", branch) with git.transaction() as transaction: git.fetch("origin") if ref: to_reset = ref git.reset("--hard", to_reset) else: git.reset("--hard", "origin/%s" % branch) if not transaction.ok: raise Exception("Update failed\n" + transaction.output)
def _sync_manifest(self): """ Update the local manifest clone with the remote """ git = qisrc.git.Git(self.manifest_repo) git.set_remote("origin", self.manifest.url) if git.get_current_branch() != self.manifest.branch: git.checkout("-B", self.manifest.branch) with git.transaction() as transaction: git.fetch("origin") if self.manifest.ref: to_reset = self.manifest.ref git.reset("--hard", to_reset) else: git.reset("--hard", "origin/%s" % self.manifest.branch) if not transaction.ok: raise Exception("Update failed\n" + transaction.output)
def test_when_not_on_a_branch(git_server, qisrc_action, record_messages): git_server.create_repo("foo.git") git_server.switch_manifest_branch("devel") git_server.change_branch("foo.git", "devel") git_server.push_file("foo.git", "devel", "this is devel\n", branch="devel", message="start developing") qisrc_action("init", git_server.manifest_url, "--branch", "devel") git_worktree = TestGitWorkTree() foo = git_worktree.get_git_project("foo") git = qisrc.git.Git(foo.path) git.checkout("HEAD~1") record_messages.reset() qisrc_action("log", "--all", "master") assert record_messages.find("Not on a branch")
def push_tag(self, project, tag, branch="master", fast_forward=True): """ push tag on project """ src = project.replace(".git", "") repo_src = self.src.join(src) git = qisrc.git.Git(repo_src.strpath) if git.get_current_branch() != branch: git.checkout("--force", "-B", branch) if not fast_forward: git.reset("--hard", "HEAD~1") # tag the branch git.call("tag", tag) if fast_forward: git.push("origin", tag) else: git.push("origin", "--force", tag)
def test_when_not_on_a_branch(git_server, qisrc_action, record_messages): """ Test When Not On a Branch """ git_server.create_repo("foo.git") git_server.switch_manifest_branch("devel") git_server.change_branch("foo.git", "devel") git_server.push_file("foo.git", "devel", "this is devel\n", branch="devel", message="start developing") qisrc_action("init", git_server.manifest_url, "--branch", "devel") git_worktree = TestGitWorkTree() foo1 = git_worktree.get_git_project("foo") git = qisrc.git.Git(foo1.path) git.checkout("HEAD~1") record_messages.reset() qisrc_action("log", "--all", "master") assert record_messages.find("Not on a branch")
def _clone_missing(self, git_project, repo): branch = repo.default_branch clone_url = repo.clone_url qisys.sh.mkdir(git_project.path, recursive=True) git = qisrc.git.Git(git_project.path) remote_name = repo.default_remote.name try: git.init() git.remote("add", remote_name, clone_url) git.fetch(remote_name, "--quiet") git.checkout("-b", branch, "%s/%s" % (remote_name, branch)) except: ui.error("Cloning repo failed") if git.is_empty(): qisys.sh.rm(git_project.path) self.worktree.remove_project(repo.src) return False self.save_project_config(git_project) self.load_git_projects() return True
def push_file(tmp, git_path, filename, contents, branch="master"): """ Push a file to the given url. Assumes the repository has been created with :py:func:`create_git_repo` with the same path """ tmp_src = os.path.join(tmp, "src", git_path) tmp_srv = os.path.join(tmp, "srv", git_path + ".git") git = qisrc.git.Git(tmp_src) if branch in git.get_local_branches(): git.checkout("-f", branch) else: git.checkout("-b", branch) dirname = os.path.dirname(filename) qibuild.sh.mkdir(os.path.join(tmp_src, dirname), recursive=True) with open(os.path.join(tmp_src, filename), "w") as fp: fp.write(contents) git.add(filename) git.commit("-m", "added %s" % filename) git.push(tmp_srv, "%s:%s" % (branch, branch))
def test_wrong_branch_with_conflicts(self): bar_url = create_git_repo(self.tmp, "bar") work = os.path.join(self.tmp, "work") qibuild.sh.mkdir(work) bar_src = os.path.join(work, "bar") git = qisrc.git.Git(bar_src) git.clone(bar_url) # Create conflicting changes write_readme(bar_src, "conflicting changes\n", append=True) git.commit("-a", "-m", "conflicting changes") push_readme_v2(self.tmp, "bar", "master") # Checkout an other branch git.checkout("-b", "next") # Try to update master while being on an other branch: err = git.update_branch("master", "origin") self.assertTrue(err) self.assertTrue("Merge is not fast-forward" in err)
def test_set_tracking_branch(tmpdir): tmpdir = tmpdir.strpath bar_url = create_git_repo(tmpdir, "bar") work = os.path.join(tmpdir, "work") bar_src = os.path.join(work, "bar") git = qisrc.git.Git(bar_src) git.clone(bar_url) push_file(tmpdir, "bar", "README", "README on release", branch="release") push_file(tmpdir, "bar", "README", "README on master", branch="master") git.update_branch("master", "origin") git.set_tracking_branch("release", "origin") err = git.update_branch("release", "origin") assert not err # This should work out of the box git.pull() git.checkout("release") git.pull()
def _switch_to_git_ref(git, ref_to_reset_to, is_tag): """ Switch To Git Ref """ if is_tag: # checkout puts the git current repo in a detached HEAD status # As setting a tag in the manifest means oubvioulsy a read-only git copy, # The detached HEAD prevents an user to accidentally pull up to the original branch HEAD and commits things rc, out = git.checkout(ref_to_reset_to, "--", raises=False) else: # reset --hard keeps the attached HEAD, and that's probably what the user needs to be able to track changes # and commits some things. If the user wants its git copy in read-only, he can use a tag instead of a branch rc, out = git.reset("--hard", ref_to_reset_to, "--", raises=False) return rc, out
def _sync_manifest(self): """ Update the local manifest clone with the remote """ if not self.manifest.url: mess = """ \ No manifest set for worktree in {root} Please run `qisrc init MANIFEST_URL` """ raise Exception(mess.format(root=self.git_worktree.root)) git = qisrc.git.Git(self.manifest_repo) git.set_remote("origin", self.manifest.url) if git.get_current_branch() != self.manifest.branch: git.checkout("-B", self.manifest.branch) with git.transaction() as transaction: git.fetch("origin") if self.manifest.ref: to_reset = self.manifest.ref git.reset("--hard", to_reset) else: git.reset("--hard", "origin/%s" % self.manifest.branch) if not transaction.ok: raise Exception("Update failed\n" + transaction.output)
def _clone_missing(self, git_project, repo): branch = repo.default_branch clone_url = repo.clone_url qisys.sh.mkdir(git_project.path, recursive=True) git = qisrc.git.Git(git_project.path) remote_name = repo.default_remote.name try: git.init() git.remote("add", remote_name, clone_url) git.fetch(remote_name, "--quiet") remote_branch = "%s/%s" % (remote_name, branch) rc, _ = git.call("rev-parse", "--verify", "--quiet", remote_branch, raises=False) # When `remote_branch` is invalid, try to checkout `branch` instead git.checkout("-b", branch, branch if rc else remote_branch) except: ui.error("Cloning repo failed") if git.is_empty(): qisys.sh.rm(git_project.path) self.worktree.remove_project(repo.src) return False self.save_project_config(git_project) self.load_git_projects() return True
def test_set_remote(self): bar_url = create_git_repo(self.tmp, "bar", with_release_branch=True) work = os.path.join(self.tmp, "work") qibuild.sh.mkdir(work) bar_src = os.path.join(work, "bar") git = qisrc.git.Git(bar_src) git.clone(bar_url, "-o", "foo") # Must work: git.pull() git.set_remote("origin", bar_url) # Must NOT work: out, err_ = git.pull("origin", raises=False) self.assertFalse(out == 0) # Must work git.set_tracking_branch("master", "origin") git.pull() readme = read_readme(bar_src) self.assertEqual(readme, "bar\n") git.set_tracking_branch("stable", "origin", remote_branch="release-1.12") git.checkout("stable") git.pull() readme = read_readme(bar_src) self.assertEqual(readme, "bar on release-1.12\n")