Skip to content

Git

blame_copy(context, original_path, destination_paths)

Copy file from original path to destination paths with saving blame.

If destination path is file, then data will be copied in it. If destination path is directory, then data will be copied in provided directory with original name. How script works: 1) Remember current HEAD state 2) For each copy path: move file to copy path, restore file using checkout, remember result commits 3) Restore state of branch 4) Move file to temp file 5) Merge copy commits to branch 6) Move file to it's original path from temp file Count of created commits: N + 3, where N - is count of copies, 3 - 1 commit to put original file to temp file 1 commit to merge commits with creation of copy files 1 commit to put data from temp file to original file back.

Source code in saritasa_invocations/git.py
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
@invoke.task
def blame_copy(
    context: invoke.Context,
    original_path: str,
    destination_paths: str,
) -> None:
    """Copy file from original path to destination paths with saving blame.

    If destination path is file, then data will be copied in it.
    If destination path is directory, then data will be copied in provided
    directory with original name.
    How script works:
        1) Remember current HEAD state
        2) For each copy path:
            move file to copy path, restore file using `checkout`,
            remember result commits
        3) Restore state of branch
        4) Move file to temp file
        5) Merge copy commits to branch
        6) Move file to it's original path from temp file
    Count of created commits:
        N + 3, where N - is count of copies,
        3 - 1 commit to put original file to temp file
        1 commit to merge commits with creation of copy files
        1 commit to put data from temp file to original file back.

    """
    config = _config.Config.from_context(context)
    destination_paths_list = _split_destination_paths(destination_paths)
    printing.print_success("Validating provided paths")
    _validate_paths(original_path, destination_paths_list)
    printing.print_success(
        config.git.copy_init_message_template.format(
            original_path=original_path,
            destination_paths="\n* ".join(destination_paths_list),
            commits_count=len(destination_paths_list) + 3,
        ),
    )
    _display_continue_prompt()
    # formatted commit template with only space for action
    printing.print_success("Build formatted commit")
    formatted_commit_template = config.git.copy_commit_template.format(
        action="{action}",
        original_path=original_path,
        destination_paths="\n* ".join(destination_paths_list),
        project_task=_build_task_string(context=context),
    )

    # temp file to save original file
    printing.print_success("Create temp file")
    temp_file = _get_command_output(
        context=context,
        command=f"mktemp ./{destination_paths_list[0]}.XXXXXX",
    )

    # current HEAD state
    printing.print_success("Get current HEAD sha")
    root_commit = _get_command_output(
        context=context,
        command="git rev-parse HEAD",
    )

    # create copies with blame of original
    printing.print_success("Create copies with blame of original file")
    copy_commits = _copy_files(
        context=context,
        original_path=original_path,
        destination_paths=destination_paths_list,
        root_commit=root_commit,
        commit_template=formatted_commit_template,
    )

    # put original file to temp copy
    printing.print_success("Restore branch to original state")
    context.run("git reset --hard HEAD^")
    printing.print_success(f"Move {original_path} to temp file")
    _move_file(
        context=context,
        from_path=original_path,
        to_path=temp_file,
        options=["-f"],
        message=formatted_commit_template.format(
            action=f"put {original_path} to temp file",
        ),
    )

    # merge copy commits
    printing.print_success("Merge copy commits")
    _merge_commits(
        context=context,
        commits=copy_commits,
        message=formatted_commit_template.format(action="merge"),
    )

    # move original file back
    printing.print_success(f"Move data from temp file to {original_path}")
    _move_file(
        context=context,
        from_path=temp_file,
        to_path=original_path,
        message=formatted_commit_template.format(
            action=f"put temp file data to {original_path}",
        ),
    )
    printing.print_success("Success")

checkout_to_branch(context, repo_path, branch, checkout_params='')

Checkout to repo's branch.

Source code in saritasa_invocations/git.py
75
76
77
78
79
80
81
82
83
84
85
86
def checkout_to_branch(
    context: invoke.Context,
    repo_path: str | pathlib.Path,
    branch: str,
    checkout_params: str = "",
) -> None:
    """Checkout to repo's branch."""
    if not branch:
        return
    with context.cd(repo_path):
        printing.print_success(f"Checkout to `{branch}` branch")
        context.run(f"git checkout {branch} {checkout_params}")

clone_repo(context, repo_link, repo_path, branch='', clone_params='', pull_params='', checkout_params='')

Clone repo for work to folder.

Source code in saritasa_invocations/git.py
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
@invoke.task
def clone_repo(
    context: invoke.Context,
    repo_link: str,
    repo_path: str | pathlib.Path,
    branch: str = "",
    clone_params: str = "",
    pull_params: str = "",
    checkout_params: str = "",
) -> None:
    """Clone repo for work to folder."""
    if not pathlib.Path(repo_path).exists():
        printing.print_success(
            f"Cloning `{repo_link}` repository to `{repo_path}`",
        )
        context.run(f"git clone {repo_link} {repo_path} {clone_params}")
        checkout_to_branch(
            context,
            repo_path=repo_path,
            branch=branch,
            checkout_params=checkout_params,
        )
        printing.print_success(f"Successfully cloned to `{repo_path}`")
    else:
        printing.print_success(
            f"Pulling changes for `{repo_link}` in `{repo_path}`",
        )
        checkout_to_branch(
            context,
            repo_path=repo_path,
            branch=branch,
            checkout_params=checkout_params,
        )
        with context.cd(repo_path):
            context.run(f"git pull {pull_params}")

set_git_setting(context, setting, value)

Set git setting in config.

Source code in saritasa_invocations/git.py
29
30
31
32
33
34
35
def set_git_setting(
    context: invoke.Context,
    setting: str,
    value: str,
) -> None:
    """Set git setting in config."""
    context.run(f"git config --local --add {setting} {value}")

setup(context)

Set up git for working.

Source code in saritasa_invocations/git.py
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@invoke.task
def setup(context: invoke.Context) -> None:
    """Set up git for working."""
    printing.print_success("Setting up git and pre-commit")
    pre_commit.install(context)

    config = _config.Config.from_context(context)
    set_git_setting(
        context,
        setting="merge.ff",
        value=config.git.merge_ff,
    )
    set_git_setting(
        context,
        setting="pull.ff",
        value=config.git.pull_ff,
    )