Name | git-clipboard JSON |
Version |
0.2.1
JSON |
| download |
home_page | None |
Summary | Cut and paste Git history safely using bundles and git-filter-repo, with strong dry-run previews |
upload_time | 2025-08-30 20:54:17 |
maintainer | None |
docs_url | None |
author | vv111y |
requires_python | >=3.8 |
license | MIT |
keywords |
bundle
git
git-filter-repo
history
subtree
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# git-clipboard
Convenience CLI wrappers to cut and paste Git history using git-filter-repo and bundles.
- git-cut: produce a portable bundle containing only selected paths and their full history.
- git-paste: import that bundle into another repository, preserving history and optionally merging.
The heavy lifting is done by git-filter-repo; these commands try to make common flows one-liners.
## Install
- Requirements: git, git-filter-repo
- macOS: `brew install git-filter-repo`
Python package (pipx) install for convenience:
```bash
pipx install .
# Afterwards the commands git-cut, git-paste, git-clipboard are available on your PATH
```
## git-cut
Create a bundle containing only the specified paths (files/folders) and their history. The source repo is never modified.
Usage
```bash
git-cut [PATH ...] [--repo REPO] [--to-subdir DIR] [--out-dir DIR] [--name NAME] [--force]
```
### Key options
- -r/--repo: path to the source repository (default: current dir)
- -t/--to-subdir: re-root the content into a subdirectory inside the clip
- -o/--out-dir: where to write the .bundle and .json (default: ./.git-clipboard)
- -n/--name: base filename for the outputs (default: clip-YYYYmmdd-HHMMSS)
- -f/--force: overwrite existing outputs
- -d/--dry-run: print a JSON plan without creating output files
### Outputs
- NAME.bundle: a git bundle with all refs from the filtered repo
- NAME.json: metadata capturing paths, subdir, source remotes, and default branch
- The last clip pointer is also written to ~/.git-clipboard/last for easy pasting without specifying a path.
## git-paste
Import a previously created bundle into a target repository. By default it creates a new branch from the bundle and you can choose to merge it.
Usage
```bash
git-paste [BUNDLE] [-m META.json] [-r REPO] [-a NAME] [--ref REF] [--list-refs|-L] [-b BRANCH] [--merge|-M|--squash|-s|--rebase|-R] [--no-ff|-F] [--message|-j MSG] [--dry-run|-d] [--allow-unrelated-histories|-U] [--prompt-merge|-p] [--trailers|-T]
```
### Default behavior
- Creates a branch `clip/<bundle-base-name>` from the bundle's first head
- If --merge/--squash/--rebase is given, merges into the current branch (or --branch)
- Cleans up a temporary remote used for fetching from the bundle
### Ref selection
- Use `--ref` to pick a specific ref from the bundle (e.g., `--ref main` or `--ref refs/heads/main`).
- If omitted, git-paste tries the metadata `default_branch` from the clip. If not available, it falls back to the first head in the bundle.
### List refs in a bundle
- Use `--list-refs` (`-L`) to print all refs in the bundle as JSON and exit.
- If a metadata file is available, `default_ref` will be included based on the clip’s `default_branch`.
Example:
```bash
git-paste ./clips/clip.bundle --list-refs
# {
# "action": "list-refs",
# "bundle": "/abs/path/clips/clip.bundle",
# "refs": [
# {"sha": "abc123", "ref": "refs/heads/main"}
# ],
# "default_ref": "refs/heads/main"
# }
```
### Clipboard default and obvious mode
- If BUNDLE is omitted, git-paste looks up the last clip pointer at `~/.git-clipboard/last` written by git-cut, and uses that bundle.
- If you pass no merge flags, git-paste runs a quick merge preview and, if clean, prompts whether to auto-merge the imported branch into the current (or --branch) target. If conflicts are likely or unknown, it won’t auto-merge.
Example (clipboard + obvious mode):
```bash
# In source repo
git-cut path/to/subtree --out-dir ../clips --to-subdir imported
# In target repo, just paste with no args. If clean, confirm to auto-merge.
git-paste
```
### Trailers (provenance in commit messages)
- Use `--trailers` (`-T`) to append clip metadata as trailers to merge or squash commit messages.
- Trailers include: `Clip-Bundle`, `Clip-Source` (if available), `Clip-Paths`, `Clip-Subdir`, `Clip-Created-At`, `Clip-Ref` (imported ref), and `Clip-Head` (SHA of imported branch head).
- Behavior:
- If you pass `--message`, trailers are added as an extra paragraph.
- If you don’t pass `--message`, for non-squash merges the default merge message is preserved and we amend to append trailers.
- For squash merges, trailers are appended to the squash commit message.
Example:
```bash
git-paste ../clips/clip.bundle --merge --allow-unrelated-histories --message "Import clip" --trailers
# Commit message ends with:
# Clip-Bundle: clip.bundle
# Clip-Source: git@github.com:me/repo.git
# Clip-Paths: proj/a
# Clip-Subdir: imported
# Clip-Created-At: 2025-01-01T12:00:00Z
# Clip-Ref: refs/heads/main
# Clip-Head: abcdef1234567890...
```
### Notes for dry-run
- With `--dry-run`, paste clones the target repo into a temporary directory, simulates the import and prints a JSON summary, and previews merge conflicts using `git merge-tree` when possible. The real repo is not modified.
- Use `--allow-unrelated-histories` when you later perform a real merge of unrelated histories (often required for fresh repos).
- Use `--prompt-merge` to preview conflicts and, if clean, interactively confirm an automatic merge.
### Dry-run JSON fields
- import-branch: action, as_branch, source_ref, remote, head, source_summary
- source_summary now includes: commit_count, top_level_paths (+ totals), file_count, total_size_bytes, largest_files[{path,size}]
- merge-preview: action, target, source, no_ff, squash, conflicts, allow_unrelated_histories, auto_allow_unrelated_histories, trailers, source_summary, diff_summary, note
- diff_summary: range, files_changed, insertions, deletions, changes_sample (up to 50 items; includes rename tuples)
- head: SHA of the imported branch tip
- source_summary: quick provenance of the imported branch
- commit_count: integer
- top_level_paths: up to 50 entries from the branch root
- top_level_paths_total: total entries
- top_level_paths_truncated: true if truncated
- merge-preview includes:
- target, source, no_ff, squash, conflicts
- allow_unrelated_histories, auto_allow_unrelated_histories, trailers
- source_summary: same shape as above
- note: reason when merge-base is unknown
## Notes and assumptions
- Assumes git-filter-repo is installed and available as either `git filter-repo` or `git-filter-repo`.
- `git-cut` clones your repository into a temp directory, filters there, and never touches your working copy.
- We bundle `--all` refs after filtering to maximize portability; paste selects the first head by default.
- If you used `--to-subdir` when cutting, the directory structure is already remapped inside the bundle; paste doesn’t need to move files.
- Merge strategies in paste are standard Git merge/rebase flows; resolve conflicts as usual if they arise.
## Examples
Cut history of two folders and paste into another repo under a new branch, then merge:
```bash
# from source repo
git-cut dotfiles/.config nvim/ --to-subdir configs --out-dir ../clips
# in target repo
git-paste ../clips/clip-20250101-120000.bundle --dry-run --merge
# If clean, perform the merge (often with unrelated histories allowed):
git-paste ../clips/clip-20250101-120000.bundle --merge --allow-unrelated-histories --message "Import configs"
```
## Try it
Quick smoke test and demo:
```bash
# Run the end-to-end test; it prints JSON previews and ends with "E2E OK"
bash ./e2e.sh
```
Minimal clipboard flow:
```bash
# In a source repo
git-cut some/path --to-subdir imported
# In a target repo
git-paste # uses the last clip; if clean, confirm to auto-merge
```
## Tests
Run the end-to-end test script (creates temporary repos, cuts, dry-runs paste, then imports and merges):
```bash
bash ./e2e.sh
```
## Troubleshooting
- If you see `git: 'filter-repo' is not a git command`, install git-filter-repo.
- Bundles list heads: `git bundle list-heads path/to.bundle`.
- You can delete the generated branch and retry paste safely; the origin repo is never modified by these tools.
## License
MIT
Raw data
{
"_id": null,
"home_page": null,
"name": "git-clipboard",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "bundle, git, git-filter-repo, history, subtree",
"author": "vv111y",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/cf/d1/6d2a513430bf13d7acab505aba944d619ea9c1a2d0a5877c0c5527e05a27/git_clipboard-0.2.1.tar.gz",
"platform": null,
"description": "# git-clipboard\n\nConvenience CLI wrappers to cut and paste Git history using git-filter-repo and bundles.\n\n- git-cut: produce a portable bundle containing only selected paths and their full history.\n- git-paste: import that bundle into another repository, preserving history and optionally merging.\n\nThe heavy lifting is done by git-filter-repo; these commands try to make common flows one-liners.\n\n## Install\n\n- Requirements: git, git-filter-repo\n- macOS: `brew install git-filter-repo`\n\nPython package (pipx) install for convenience:\n\n```bash\npipx install .\n# Afterwards the commands git-cut, git-paste, git-clipboard are available on your PATH\n```\n\n## git-cut\n\nCreate a bundle containing only the specified paths (files/folders) and their history. The source repo is never modified.\n\nUsage\n\n```bash\ngit-cut [PATH ...] [--repo REPO] [--to-subdir DIR] [--out-dir DIR] [--name NAME] [--force]\n```\n\n### Key options\n\n- -r/--repo: path to the source repository (default: current dir)\n- -t/--to-subdir: re-root the content into a subdirectory inside the clip\n- -o/--out-dir: where to write the .bundle and .json (default: ./.git-clipboard)\n- -n/--name: base filename for the outputs (default: clip-YYYYmmdd-HHMMSS)\n- -f/--force: overwrite existing outputs\n- -d/--dry-run: print a JSON plan without creating output files\n\n### Outputs\n\n- NAME.bundle: a git bundle with all refs from the filtered repo\n- NAME.json: metadata capturing paths, subdir, source remotes, and default branch\n- The last clip pointer is also written to ~/.git-clipboard/last for easy pasting without specifying a path.\n\n## git-paste\n\nImport a previously created bundle into a target repository. By default it creates a new branch from the bundle and you can choose to merge it.\n\nUsage\n\n```bash\ngit-paste [BUNDLE] [-m META.json] [-r REPO] [-a NAME] [--ref REF] [--list-refs|-L] [-b BRANCH] [--merge|-M|--squash|-s|--rebase|-R] [--no-ff|-F] [--message|-j MSG] [--dry-run|-d] [--allow-unrelated-histories|-U] [--prompt-merge|-p] [--trailers|-T]\n```\n\n### Default behavior\n\n- Creates a branch `clip/<bundle-base-name>` from the bundle's first head\n- If --merge/--squash/--rebase is given, merges into the current branch (or --branch)\n- Cleans up a temporary remote used for fetching from the bundle\n\n### Ref selection\n\n- Use `--ref` to pick a specific ref from the bundle (e.g., `--ref main` or `--ref refs/heads/main`).\n- If omitted, git-paste tries the metadata `default_branch` from the clip. If not available, it falls back to the first head in the bundle.\n\n### List refs in a bundle\n\n- Use `--list-refs` (`-L`) to print all refs in the bundle as JSON and exit.\n- If a metadata file is available, `default_ref` will be included based on the clip\u2019s `default_branch`.\n\nExample:\n\n```bash\ngit-paste ./clips/clip.bundle --list-refs\n# {\n# \"action\": \"list-refs\",\n# \"bundle\": \"/abs/path/clips/clip.bundle\",\n# \"refs\": [\n# {\"sha\": \"abc123\", \"ref\": \"refs/heads/main\"}\n# ],\n# \"default_ref\": \"refs/heads/main\"\n# }\n```\n\n### Clipboard default and obvious mode\n\n- If BUNDLE is omitted, git-paste looks up the last clip pointer at `~/.git-clipboard/last` written by git-cut, and uses that bundle.\n- If you pass no merge flags, git-paste runs a quick merge preview and, if clean, prompts whether to auto-merge the imported branch into the current (or --branch) target. If conflicts are likely or unknown, it won\u2019t auto-merge.\n\nExample (clipboard + obvious mode):\n\n```bash\n# In source repo\ngit-cut path/to/subtree --out-dir ../clips --to-subdir imported\n\n# In target repo, just paste with no args. If clean, confirm to auto-merge.\ngit-paste\n```\n\n### Trailers (provenance in commit messages)\n\n- Use `--trailers` (`-T`) to append clip metadata as trailers to merge or squash commit messages.\n- Trailers include: `Clip-Bundle`, `Clip-Source` (if available), `Clip-Paths`, `Clip-Subdir`, `Clip-Created-At`, `Clip-Ref` (imported ref), and `Clip-Head` (SHA of imported branch head).\n- Behavior:\n\t- If you pass `--message`, trailers are added as an extra paragraph.\n\t- If you don\u2019t pass `--message`, for non-squash merges the default merge message is preserved and we amend to append trailers.\n\t- For squash merges, trailers are appended to the squash commit message.\n\nExample:\n\n```bash\ngit-paste ../clips/clip.bundle --merge --allow-unrelated-histories --message \"Import clip\" --trailers\n# Commit message ends with:\n# Clip-Bundle: clip.bundle\n# Clip-Source: git@github.com:me/repo.git\n# Clip-Paths: proj/a\n# Clip-Subdir: imported\n# Clip-Created-At: 2025-01-01T12:00:00Z\n# Clip-Ref: refs/heads/main\n# Clip-Head: abcdef1234567890...\n```\n\n### Notes for dry-run\n\n- With `--dry-run`, paste clones the target repo into a temporary directory, simulates the import and prints a JSON summary, and previews merge conflicts using `git merge-tree` when possible. The real repo is not modified.\n- Use `--allow-unrelated-histories` when you later perform a real merge of unrelated histories (often required for fresh repos).\n- Use `--prompt-merge` to preview conflicts and, if clean, interactively confirm an automatic merge.\n\n### Dry-run JSON fields\n\n- import-branch: action, as_branch, source_ref, remote, head, source_summary\n\t- source_summary now includes: commit_count, top_level_paths (+ totals), file_count, total_size_bytes, largest_files[{path,size}]\n- merge-preview: action, target, source, no_ff, squash, conflicts, allow_unrelated_histories, auto_allow_unrelated_histories, trailers, source_summary, diff_summary, note\n\t- diff_summary: range, files_changed, insertions, deletions, changes_sample (up to 50 items; includes rename tuples)\n\t- head: SHA of the imported branch tip\n\t- source_summary: quick provenance of the imported branch\n\t- commit_count: integer\n\t- top_level_paths: up to 50 entries from the branch root\n\t- top_level_paths_total: total entries\n\t- top_level_paths_truncated: true if truncated\n\n- merge-preview includes:\n\t- target, source, no_ff, squash, conflicts\n\t- allow_unrelated_histories, auto_allow_unrelated_histories, trailers\n\t- source_summary: same shape as above\n\t- note: reason when merge-base is unknown\n\n## Notes and assumptions\n\n- Assumes git-filter-repo is installed and available as either `git filter-repo` or `git-filter-repo`.\n- `git-cut` clones your repository into a temp directory, filters there, and never touches your working copy.\n- We bundle `--all` refs after filtering to maximize portability; paste selects the first head by default.\n- If you used `--to-subdir` when cutting, the directory structure is already remapped inside the bundle; paste doesn\u2019t need to move files.\n- Merge strategies in paste are standard Git merge/rebase flows; resolve conflicts as usual if they arise.\n\n## Examples\n\nCut history of two folders and paste into another repo under a new branch, then merge:\n\n```bash\n# from source repo\ngit-cut dotfiles/.config nvim/ --to-subdir configs --out-dir ../clips\n\n# in target repo\ngit-paste ../clips/clip-20250101-120000.bundle --dry-run --merge\n# If clean, perform the merge (often with unrelated histories allowed):\ngit-paste ../clips/clip-20250101-120000.bundle --merge --allow-unrelated-histories --message \"Import configs\"\n```\n\n## Try it\n\nQuick smoke test and demo:\n\n```bash\n# Run the end-to-end test; it prints JSON previews and ends with \"E2E OK\"\nbash ./e2e.sh\n```\n\nMinimal clipboard flow:\n\n```bash\n# In a source repo\ngit-cut some/path --to-subdir imported\n\n# In a target repo\ngit-paste # uses the last clip; if clean, confirm to auto-merge\n```\n\n## Tests\n\nRun the end-to-end test script (creates temporary repos, cuts, dry-runs paste, then imports and merges):\n\n```bash\nbash ./e2e.sh\n```\n\n## Troubleshooting\n\n- If you see `git: 'filter-repo' is not a git command`, install git-filter-repo.\n- Bundles list heads: `git bundle list-heads path/to.bundle`.\n- You can delete the generated branch and retry paste safely; the origin repo is never modified by these tools.\n\n## License\n\nMIT\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Cut and paste Git history safely using bundles and git-filter-repo, with strong dry-run previews",
"version": "0.2.1",
"project_urls": {
"Homepage": "https://github.com/vv111y/git-clipboard"
},
"split_keywords": [
"bundle",
" git",
" git-filter-repo",
" history",
" subtree"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "89a35b66c3b667a7cb171c0cc2f9917c5ac2231174be47ef378eeae046ee9c7e",
"md5": "021f7ec7f2975a4bba7b99f4ef5754e8",
"sha256": "681c36fa563e5565212a20689c14b94f82f42b799792d74583aeba31bdc2b060"
},
"downloads": -1,
"filename": "git_clipboard-0.2.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "021f7ec7f2975a4bba7b99f4ef5754e8",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 14756,
"upload_time": "2025-08-30T20:54:15",
"upload_time_iso_8601": "2025-08-30T20:54:15.896741Z",
"url": "https://files.pythonhosted.org/packages/89/a3/5b66c3b667a7cb171c0cc2f9917c5ac2231174be47ef378eeae046ee9c7e/git_clipboard-0.2.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "cfd16d2a513430bf13d7acab505aba944d619ea9c1a2d0a5877c0c5527e05a27",
"md5": "6a26192526b987f00448ea6e8568c699",
"sha256": "9e1d2ad699db8d8b7c96ec7e40a2dc6878f8f8c5810fe52328543f0a43c2bd82"
},
"downloads": -1,
"filename": "git_clipboard-0.2.1.tar.gz",
"has_sig": false,
"md5_digest": "6a26192526b987f00448ea6e8568c699",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 13883,
"upload_time": "2025-08-30T20:54:17",
"upload_time_iso_8601": "2025-08-30T20:54:17.586667Z",
"url": "https://files.pythonhosted.org/packages/cf/d1/6d2a513430bf13d7acab505aba944d619ea9c1a2d0a5877c0c5527e05a27/git_clipboard-0.2.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-30 20:54:17",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "vv111y",
"github_project": "git-clipboard",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "git-clipboard"
}