#!/usr/bin/env python3 import os import re import git import pytest from helpers import TempGitRepositoryWorktree, funcname, grm, shell @pytest.mark.parametrize("pull", [True, False]) @pytest.mark.parametrize("rebase", [True, False]) @pytest.mark.parametrize("ffable", [True, False]) @pytest.mark.parametrize("has_changes", [True, False]) @pytest.mark.parametrize("stash", [True, False]) def test_worktree_rebase(pull, rebase, ffable, has_changes, stash): with TempGitRepositoryWorktree.get(funcname()) as (base_dir, _root_commit): with open(os.path.join(base_dir, "grm.toml"), "w") as f: f.write('persistent_branches = ["mybasebranch"]') repo = git.Repo(f"{base_dir}/.git-main-working-tree") grm( ["wt", "add", "mybasebranch", "--track", "origin/mybasebranch"], cwd=base_dir, ) shell( f""" cd {base_dir}/mybasebranch echo change > mychange-root git add mychange-root git commit -m "commit-root" echo change > mychange-base-local git add mychange-base-local git commit -m "commit-in-base-local" git push origin mybasebranch """ ) grm( ["wt", "add", "myfeatbranch", "--track", "origin/myfeatbranch"], cwd=base_dir, ) shell( f""" cd {base_dir}/myfeatbranch git reset --hard mybasebranch^ # root echo change > mychange-feat-local git add mychange-feat-local git commit -m "commit-in-feat-local" git push origin HEAD:myfeatbranch """ ) grm(["wt", "add", "tmp"], cwd=base_dir) shell( f""" cd {base_dir}/tmp git reset --hard mybasebranch echo change > mychange-base-remote git add mychange-base-remote git commit -m "commit-in-base-remote" git push origin HEAD:mybasebranch git reset --hard myfeatbranch echo change > mychange-feat-remote git add mychange-feat-remote git commit -m "commit-in-feat-remote" git push origin HEAD:myfeatbranch """ ) if not ffable: shell( f""" cd {base_dir}/mybasebranch echo change > mychange-base-no-ff git add mychange-base-no-ff git commit -m "commit-in-base-local-no-ff" cd {base_dir}/myfeatbranch echo change > mychange-feat-no-ff git add mychange-feat-no-ff git commit -m "commit-in-feat-local-no-ff" """ ) if has_changes: shell( f""" cd {base_dir}/myfeatbranch echo uncommitedchange > uncommitedchange """ ) grm(["wt", "delete", "--force", "tmp"], cwd=base_dir) repo = git.Repo(f"{base_dir}/.git-main-working-tree") if ffable: assert repo.commit("mybasebranch~1").message.strip() == "commit-root" assert ( repo.refs.mybasebranch.commit.message.strip() == "commit-in-base-local" ) assert ( repo.remote("origin").refs.mybasebranch.commit.message.strip() == "commit-in-base-remote" ) assert ( repo.refs.myfeatbranch.commit.message.strip() == "commit-in-feat-local" ) assert ( repo.remote("origin").refs.myfeatbranch.commit.message.strip() == "commit-in-feat-remote" ) else: assert ( repo.commit("mybasebranch").message.strip() == "commit-in-base-local-no-ff" ) assert ( repo.commit("mybasebranch~1").message.strip() == "commit-in-base-local" ) assert repo.commit("mybasebranch~2").message.strip() == "commit-root" assert ( repo.commit("myfeatbranch").message.strip() == "commit-in-feat-local-no-ff" ) assert ( repo.commit("myfeatbranch~1").message.strip() == "commit-in-feat-local" ) assert repo.commit("myfeatbranch~2").message.strip() == "commit-root" assert ( repo.remote("origin").refs.mybasebranch.commit.message.strip() == "commit-in-base-remote" ) assert ( repo.remote("origin").refs.myfeatbranch.commit.message.strip() == "commit-in-feat-remote" ) args = ["wt", "rebase"] if pull: args += ["--pull"] if rebase: args += ["--rebase"] if stash: args += ["--stash"] cmd = grm(args, cwd=base_dir) if rebase and not pull: assert cmd.returncode != 0 assert len(cmd.stderr) != 0 elif has_changes and not stash: assert cmd.returncode != 0 assert re.search(r".*myfeatbranch.*contains changes.*", cmd.stderr) else: repo = git.Repo(f"{base_dir}/myfeatbranch") if has_changes: assert ["uncommitedchange"] == repo.untracked_files if pull: if rebase: assert cmd.returncode == 0 if ffable: assert ( repo.commit("HEAD").message.strip() == "commit-in-feat-remote" ) assert ( repo.commit("HEAD~1").message.strip() == "commit-in-feat-local" ) assert ( repo.commit("HEAD~2").message.strip() == "commit-in-base-remote" ) assert ( repo.commit("HEAD~3").message.strip() == "commit-in-base-local" ) assert repo.commit("HEAD~4").message.strip() == "commit-root" else: assert ( repo.commit("HEAD").message.strip() == "commit-in-feat-local-no-ff" ) assert ( repo.commit("HEAD~1").message.strip() == "commit-in-feat-remote" ) assert ( repo.commit("HEAD~2").message.strip() == "commit-in-feat-local" ) assert ( repo.commit("HEAD~3").message.strip() == "commit-in-base-local-no-ff" ) assert ( repo.commit("HEAD~4").message.strip() == "commit-in-base-remote" ) assert ( repo.commit("HEAD~5").message.strip() == "commit-in-base-local" ) assert repo.commit("HEAD~6").message.strip() == "commit-root" else: if ffable: assert cmd.returncode == 0 assert ( repo.commit("HEAD").message.strip() == "commit-in-feat-remote" ) assert ( repo.commit("HEAD~1").message.strip() == "commit-in-feat-local" ) assert ( repo.commit("HEAD~2").message.strip() == "commit-in-base-remote" ) assert ( repo.commit("HEAD~3").message.strip() == "commit-in-base-local" ) assert repo.commit("HEAD~4").message.strip() == "commit-root" else: assert cmd.returncode != 0 assert ( repo.commit("HEAD").message.strip() == "commit-in-feat-local-no-ff" ) assert ( repo.commit("HEAD~1").message.strip() == "commit-in-feat-local" ) assert ( repo.commit("HEAD~2").message.strip() == "commit-in-base-local-no-ff" ) assert ( repo.commit("HEAD~3").message.strip() == "commit-in-base-local" ) assert repo.commit("HEAD~4").message.strip() == "commit-root" else: assert cmd.returncode == 0 if ffable: assert repo.commit("HEAD").message.strip() == "commit-in-feat-local" assert ( repo.commit("HEAD~1").message.strip() == "commit-in-base-local" ) assert repo.commit("HEAD~2").message.strip() == "commit-root" else: assert ( repo.commit("HEAD").message.strip() == "commit-in-feat-local-no-ff" ) assert ( repo.commit("HEAD~1").message.strip() == "commit-in-feat-local" ) assert ( repo.commit("HEAD~2").message.strip() == "commit-in-base-local-no-ff" ) assert ( repo.commit("HEAD~3").message.strip() == "commit-in-base-local" ) assert repo.commit("HEAD~4").message.strip() == "commit-root"