mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
Subrepo command wasn't checked in correctly (#1737)
* Remove subrepo * Fix subrepo
This commit is contained in:
parent
73be8fb5df
commit
f4ba976121
189 changed files with 12841 additions and 1 deletions
|
|
@ -1 +0,0 @@
|
|||
Subproject commit cce3d93e1ad5dbb93c54fb78bd0eeec576eb98fb
|
||||
1
build/git-subrepo/.gitattributes
vendored
Normal file
1
build/git-subrepo/.gitattributes
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
* text eol=lf
|
||||
12
build/git-subrepo/.gitrepo
Normal file
12
build/git-subrepo/.gitrepo
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
; DO NOT EDIT (unless you know what you are doing)
|
||||
;
|
||||
; This subdirectory is a git "subrepo", and this file is maintained by the
|
||||
; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
|
||||
;
|
||||
[subrepo]
|
||||
remote = https://github.com/ingydotnet/git-subrepo.git
|
||||
branch = 0.4.1
|
||||
commit = a04d8c2e55c31931d66b5c92ef6d4fe4c59e3226
|
||||
parent = b341532bdd2eacaddca2d9c63421ef3ac9d3d239
|
||||
method = merge
|
||||
cmdver = 0.4.1
|
||||
38
build/git-subrepo/.rc
Normal file
38
build/git-subrepo/.rc
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#!bash
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# This is the `git-subrepo` initialization script.
|
||||
#
|
||||
# This script turns on the `git-subrepo` Git subcommand, its manpages and TAB
|
||||
# completion for the *Bash* and *zsh* shells.
|
||||
#
|
||||
# Just add a line like this to your shell startup configuration:
|
||||
#
|
||||
# source /path/to/git-subrepo/.rc
|
||||
#
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
if [[ ${BASH_VERSION} ]]; then
|
||||
if [[ ${BASH_VERSINFO[0]} -lt 4 ]] ; then
|
||||
echo "The git-subrepo command requires that 'Bash 4+' is installed."
|
||||
echo "It doesn't need to be your shell, but it must be in your PATH."
|
||||
if [[ $OSTYPE == darwin* ]]; then
|
||||
echo "You appear to be on macOS."
|
||||
echo "Try: 'brew install bash'."
|
||||
echo "This will not change your user shell, it just installs 'Bash 5.x'."
|
||||
fi
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
[[ -n ${ZSH_VERSION-} ]] &&
|
||||
GIT_SUBREPO_ROOT=$0 ||
|
||||
GIT_SUBREPO_ROOT=$BASH_SOURCE
|
||||
[[ $GIT_SUBREPO_ROOT =~ ^/ ]] ||
|
||||
GIT_SUBREPO_ROOT=$PWD/$GIT_SUBREPO_ROOT
|
||||
export GIT_SUBREPO_ROOT=$(cd "$(dirname "$GIT_SUBREPO_ROOT")"; pwd)
|
||||
|
||||
export PATH=$GIT_SUBREPO_ROOT/lib:$PATH
|
||||
export MANPATH=$GIT_SUBREPO_ROOT/man:$MANPATH
|
||||
source "$GIT_SUBREPO_ROOT/share/enable-completion.sh"
|
||||
31
build/git-subrepo/.travis.yml
Normal file
31
build/git-subrepo/.travis.yml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
language: shell
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- name: Git 2.21 on Ubuntu Xenial
|
||||
dist: xenial
|
||||
language: shell
|
||||
|
||||
# === This will need to removed when Travis drops support ===
|
||||
- name: Git 2.15.1 on Ubuntu Trusty
|
||||
dist: trusty
|
||||
language: shell
|
||||
|
||||
- name: Git on Mac
|
||||
os: osx
|
||||
osx_image: xcode8.3
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- bash
|
||||
update: true
|
||||
|
||||
script:
|
||||
# NOTE: we have to make sure we're on a branch (rather than on a detached HEAD)
|
||||
# because tests rely on it.
|
||||
- git checkout -b travis-ci-dummy-branch-name
|
||||
- GIT_COMMITTER_NAME=Bob
|
||||
GIT_COMMITTER_EMAIL=bob@blob.net
|
||||
GIT_AUTHOR_NAME='Bob Blob'
|
||||
GIT_AUTHOR_EMAIL=bob@blob.net
|
||||
PROVEOPT=-v make test
|
||||
110
build/git-subrepo/Changes
Normal file
110
build/git-subrepo/Changes
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
---
|
||||
version: 0.4.1
|
||||
date: Thu Jan 9 17:11:21 CST 2020
|
||||
- Fix Bash version error messages and add to .rc
|
||||
- Nicer YAML formatting in .travis.yml
|
||||
- Wrap a long line
|
||||
- Update the docs
|
||||
- Force `make update` to always update docs
|
||||
- Don't use XXX in perl stuff
|
||||
- Add testing on MacOS
|
||||
- Remove conflicting -C from install -d commands.
|
||||
- Update version requirement documentation
|
||||
- Correct error message in branch
|
||||
- Use topo-order in subrepo branch
|
||||
- Make “git subrepo clean -f ...” delete refs correctly
|
||||
- Fix #410 Push empty repositories with recent git versions
|
||||
- Make subrepo work when run in a worktree
|
||||
- Simplify finding subrepos
|
||||
- Ask git to find the .gitrepo files
|
||||
- Doc: fix sentence repetition
|
||||
- Fix typos
|
||||
- Fixed typo
|
||||
- Travis CI not checking out a branch.
|
||||
---
|
||||
version: 0.4.0
|
||||
date: Thu Nov 8 12:26:38 CET 2018
|
||||
changes:
|
||||
- Fix #325 Do not squash main repo commits
|
||||
- Improve error message for worktree handling
|
||||
- Make version checking portable. #307
|
||||
- #307, improve version check
|
||||
- #307, update version requirement
|
||||
- Fix part #308, Add stderr output if commands fail
|
||||
- Fix #306: Add check to prevent following commits with no .gitrepo
|
||||
- Remove dry-run flag as it's not implemented. Make sure branch --force delete worktree
|
||||
- Fix #296, Replace --first-parent with --ancestry-path
|
||||
- Fix #291, specify Trusty host to get new 2.x git
|
||||
- Fix #258, add --no-tags to git fetch
|
||||
- Test that no remotes are created during clone
|
||||
- #257 Remove remote creation to avoid problems with fetch --all
|
||||
- (origin/issue/150_to_0.4.0) Fix remove-worktree, remove unused parameters
|
||||
- Regenerate completion files
|
||||
- filter-branch operation should not be done on HEAD
|
||||
- Cleanup push and add hint to push directly after pull
|
||||
- Simplify cleanup and add worktree to status
|
||||
- Add --method option to init/clone, add a 'config' command
|
||||
- Updated unit tests to support the new logic
|
||||
- Use 'git worktree' for merge/rebase
|
||||
- Update docs to reflect how things should work
|
||||
- Make it possible to specify commit messages
|
||||
- Redesign, trash the tree hash approach and use merges instead
|
||||
- Add release branches to travis-ci
|
||||
- Add --method option to init/clone, add a 'config' command
|
||||
- Detect multiple pulls, use -u flag to decide
|
||||
- Don't reuse previous commit message when using --all
|
||||
- Update the docs for pull and push
|
||||
- Update error messages when failing merge/rebase
|
||||
- Fix env var bug in test/push.t
|
||||
- Do not overwrite author information
|
||||
---
|
||||
version: 0.3.1
|
||||
date: Tue Jan 3 23:08:56 PST 2017
|
||||
changes:
|
||||
- Updated release for homebrew
|
||||
- Fix #192
|
||||
---
|
||||
version: 0.3.0
|
||||
date: Wed Dec 2 19:19:43 PST 2015
|
||||
changes:
|
||||
- Fix issue #98 and host of others (89, 91, 95, 96)
|
||||
- Adds support for the merge-base command
|
||||
- Adds stability to many commands
|
||||
- Command completion updates
|
||||
- Rename `init` to `.rc`
|
||||
- @grimmySwe++ @dzzh++ @jrosdahl++ @perlpunk++
|
||||
---
|
||||
version: 0.2.3
|
||||
date: Sun Aug 9 13:44:22 PDT 2015
|
||||
changes:
|
||||
- Fix issues #75 and #76
|
||||
---
|
||||
version: 0.2.2
|
||||
date: Wed Jul 22 09:45:13 PDT 2015
|
||||
changes:
|
||||
- Added the `init` subcommand
|
||||
- Applied doc fixes
|
||||
---
|
||||
version: 0.2.1
|
||||
date: Sat Mar 28 07:52:22 PDT 2015
|
||||
changes:
|
||||
- Allows subrepo clone to clone to an empty branch; fixes #26.
|
||||
- Refs in status
|
||||
- Empty parent set to 'none' in .gitrepo file.
|
||||
- Bug fixes
|
||||
---
|
||||
version: 0.2.0
|
||||
date: Sat Jan 24 06:22:05 PST 2015
|
||||
changes:
|
||||
- Massive overhaul
|
||||
- .gitrepo files remain the same so backwards compatible
|
||||
- Introduce the branch and commit subcommands
|
||||
- The checkout subcommand goes away
|
||||
- Operations work much smoother like normal Git flow
|
||||
- Much more testing
|
||||
- Better doc
|
||||
---
|
||||
version: 0.1.0
|
||||
date: Fri Feb 21 12:25:53 2014 -0800
|
||||
changes:
|
||||
- First version
|
||||
509
build/git-subrepo/Intro.pod
Normal file
509
build/git-subrepo/Intro.pod
Normal file
|
|
@ -0,0 +1,509 @@
|
|||
=pod
|
||||
|
||||
=for comment
|
||||
DO NOT EDIT. This Pod was generated by Swim v0.1.48.
|
||||
See http://github.com/ingydotnet/swim-pm#readme
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 Introducing Git Subrepos
|
||||
|
||||
There is a new git command called C<subrepo> that is meant to be a solid
|
||||
alternative to the C<submodule> and C<subtree> commands. All 3 of these
|
||||
commands allow you to include external repositories (pinned to specific
|
||||
commits) in your main repository. This is an often needed feature for project
|
||||
development under a source control system like Git. Unfortunately, the
|
||||
C<submodule> command is severely lacking, and the C<subtree> command (an
|
||||
attempt to make things better) is also very flawed. Fortunately, the
|
||||
C<subrepo> command is here to save the day.
|
||||
|
||||
This article will discuss how the previous commands work, and where they go
|
||||
wrong, while explaining how the new C<subrepo> command fixes the issues.
|
||||
|
||||
It should be noted that there are 3 distinct roles (ways people use repos)
|
||||
involved in discussing this topic:
|
||||
|
||||
=over
|
||||
|
||||
=item * B<owner> — The primary author and repo owner
|
||||
|
||||
=item * B<collaborators> — Other developers who contribute to the repo
|
||||
|
||||
=item * B<users> — People who simply use the repo software
|
||||
|
||||
=back
|
||||
|
||||
=head2 Introducing C<subrepo>
|
||||
|
||||
While the main point is to show how subrepo addresses the shortcomings
|
||||
of submodule and subtree, I'll start by giving a quick intro to the
|
||||
subrepo command.
|
||||
|
||||
Let's say that you have a project repo called 'freebird' and you want to have
|
||||
it include 2 other external repos, 'lynyrd' and 'skynyrd'. You would do the
|
||||
following:
|
||||
|
||||
git clone git@github.com/you/freebird
|
||||
cd freebird
|
||||
git subrepo clone git@github.com/you/lynyrd ext/lynyrd
|
||||
git subrepo clone git@github.com/you/skynyrd ext/skynyrd --branch=1975
|
||||
|
||||
What these commands do (at a high level) should be obvious. They "clone" (add)
|
||||
the repos content into the subdirectories you told them to. The details of
|
||||
what is happening to your repo will be discussed later, but adding new
|
||||
subrepos is easy. If you need to update the subrepos later:
|
||||
|
||||
git subrepo pull ext/lynyrd
|
||||
git subrepo pull ext/skynyrd --branch=1976
|
||||
|
||||
The lynyrd repo is tracking the upstream master branch, and you've changed the
|
||||
skynyrd subrepo to the 1976 branch. Since these subrepos are owned by 'you',
|
||||
you might want to change them in the context of your freebird repo. When
|
||||
things are working, you can push the subrepo changes back:
|
||||
|
||||
git subrepo push ext/lynyrd
|
||||
git subrepo push ext/skynyrd
|
||||
|
||||
Looks simple right? It's supposed to be. The intent of C<subrepo> is to do the
|
||||
right things, and to not cause problems.
|
||||
|
||||
Of course there's more to it under the hood, and that's what the rest of this
|
||||
article is about.
|
||||
|
||||
=head2 Git Submodules
|
||||
|
||||
Submodules tend to receive a lot of bad press. Here's some of it:
|
||||
|
||||
=over
|
||||
|
||||
=item * L<http://ayende.com/blog/4746/the-problem-with-git-submodules>
|
||||
|
||||
=item * L<http://somethingsinistral.net/blog/git-submodules-are-probably-not-the-answer/>
|
||||
|
||||
=item * L<http://codingkilledthecat.wordpress.com/2012/04/28/why-your-company-shouldnt-use-git-submodules/>
|
||||
|
||||
=back
|
||||
|
||||
A quick recap of some of the good and bad things about submodules:
|
||||
|
||||
Good:
|
||||
|
||||
=over
|
||||
|
||||
=item * Use an external repo in a dedicated subdir of your project.
|
||||
|
||||
=item * Pin the external repo to a specific commit.
|
||||
|
||||
=item * The C<git-submodule> command is a core part of the Git project.
|
||||
|
||||
=back
|
||||
|
||||
Bad:
|
||||
|
||||
=over
|
||||
|
||||
=item * Users have to know a repo has submodules.
|
||||
|
||||
=item * Users have to get the subrepos manually.
|
||||
|
||||
=item * Pulling a repo with submodules won't pull in the new submodule changes.
|
||||
|
||||
=item * A submodule will break if the referenced repo goes away.
|
||||
|
||||
=item * A submodule will break if a forced push removes the referenced commit.
|
||||
|
||||
=item * Can't use different submodules/commits per main project branch.
|
||||
|
||||
=item * Can't "try out" a submodule on alternate branch.
|
||||
|
||||
=item * Main repo can be pushed upstream pointing to unpushed submod commits.
|
||||
|
||||
=item * Command capability differs across Git versions.
|
||||
|
||||
=item * Often need to change remote url, to push submodule changes upstream.
|
||||
|
||||
=item * Removing or renaming a submodule requires many steps.
|
||||
|
||||
=back
|
||||
|
||||
Internally, submodules are a real mess. They give the strong impression of
|
||||
being bolted on, well after Git was designed. Some commands are aware of the
|
||||
existence of submodules (although usually half-heartedly), and many commands
|
||||
are oblivious. For instance the git-clone command has a C<--recursive> option
|
||||
to clone all subrepos, but it's not a default, so you still need to be aware
|
||||
of the need. The git-checkout command does nothing with the submodules, even
|
||||
if they are intended to differ across branches.
|
||||
|
||||
Let's talk a bit about how submodules are implemented in Git. Information
|
||||
about them is stored in 3 different places (in the top level repo directory):
|
||||
|
||||
=over
|
||||
|
||||
=item * C<.gitmodules>
|
||||
|
||||
=item * C<.git/config>
|
||||
|
||||
=item * C<.git/modules> — The submodule repo's meta data (refs/objects)
|
||||
|
||||
=back
|
||||
|
||||
So some of the information lives in the repo history (.gitmodules), but other
|
||||
info (.git/) is only known to the local repo.
|
||||
|
||||
In addition, the submodule introduces a new low level concept, to the
|
||||
commitI<tree>blob graph. Normally a git tree object points to blob (file)
|
||||
objects and more tree (directory) objects. Submodules have tree objects point
|
||||
to B<commit> objects. While this seems clever and somewhat reasonable, it also
|
||||
means that every other git command (which was built on the super clean Git
|
||||
data model) has to be aware of this new possibility (and deal with it
|
||||
appropriately).
|
||||
|
||||
The point is that, while submodules are a real need, and a lot of work has
|
||||
gone into making them work decently, they are essentially a kludge to the Git
|
||||
model, and it is quite understandable why they haven't worked out as well as
|
||||
people would expect.
|
||||
|
||||
NOTE: Submodules I<are> getting better with each release of Git, but it's
|
||||
still an endless catch up game.
|
||||
|
||||
=head2 Git Subtrees
|
||||
|
||||
One day, someone decided to think different. Instead of pointing to external
|
||||
repos, why not just include them into the main repo (but also allow them to be
|
||||
pulled and pushed separately as needed)?
|
||||
|
||||
At first this may feel like a wasteful approach. Why keep other repos
|
||||
physically inside your main one? But if you think about it abstractly, what's
|
||||
the difference? You want your users and collaborators to have all this code
|
||||
because your project needs it. So why worry about how it happens? In the end,
|
||||
the choice is yours, but I've grown very comfortable with this concept and
|
||||
I'll try to justify it well. I should note that the first paragraph of the
|
||||
C<submodule> doc suggests considering this alternative.
|
||||
|
||||
The big win here is that you can do this using the existing git model. Nothing
|
||||
new is added. You are just adding commits to a history. You can do it
|
||||
different on every branch. You can merge branches sensibly.
|
||||
|
||||
The git-subtree command seems to have been inspired by Git's subtree merge
|
||||
strategy, which it uses internally, and possibly got its name from. A subtree
|
||||
merge allows you to take a completely separate Git history and make it be a
|
||||
subdirectory of your repo.
|
||||
|
||||
Adding a subtree was the easy part. All that needed to be done after that was
|
||||
to figure out a way to pull upstream changes and push local ones back
|
||||
upstream. And that's what the C<git-subtree> command does.
|
||||
|
||||
So what's the problem with git-subtree then?
|
||||
|
||||
Well unfortunately, it drops a few balls. The main problems come down to an
|
||||
overly complicated commandline UX, poor collaborator awareness, and a fragile
|
||||
and messy implementation.
|
||||
|
||||
Good:
|
||||
|
||||
=over
|
||||
|
||||
=item * Use an external repo in a dedicated subdir of your project.
|
||||
|
||||
=item * Pin the external repo to a specific commit.
|
||||
|
||||
=item * Users get everything with a normal clone command.
|
||||
|
||||
=item * Users don't need to know that subtrees are involved.
|
||||
|
||||
=item * Can use different submodules/commits per main project branch.
|
||||
|
||||
=item * Users don't need the subtree command. Only owners and collaborators.
|
||||
|
||||
=back
|
||||
|
||||
Bad:
|
||||
|
||||
=over
|
||||
|
||||
=item * The remote url and branch info is not saved (except in the history).
|
||||
|
||||
=item * Owners and collaborators have to enter the remote for every command.
|
||||
|
||||
=item * Collaborators aren't made aware that subtrees are involved.
|
||||
|
||||
=item * Pulled history is not squashed by default.
|
||||
|
||||
=item * Creates a messy historical view. (See below)
|
||||
|
||||
=item * Bash code is complicated.
|
||||
|
||||
=item * Only one test file. Currently is failing.
|
||||
|
||||
=back
|
||||
|
||||
As you can see, subtree makes quite a few things better, but after trying it
|
||||
for a while, the experience was more annoying than submodules. For example,
|
||||
consider this usage:
|
||||
|
||||
$ git subtree add --squash --prefix=foo git@github.com:my/thing mybranch
|
||||
# weeks go by…
|
||||
$ git subtree pull --squash --prefix=foo git@github.com:my/thing mybranch
|
||||
# time to push local subtree changes back upstream
|
||||
$ git subtree push --prefix=foo git@github.com:my/thing mybranch
|
||||
|
||||
The first thing you notice is the overly verbose syntax. It's justified in the
|
||||
first command, but in the other 2 commands I really don't want to have to
|
||||
remember what the remote and branch are that I'm using.
|
||||
|
||||
Moreover, my collaborators have no idea that subtrees are involved, let alone
|
||||
where they came from.
|
||||
|
||||
Consider the equivalent subrepo commands:
|
||||
|
||||
$ git subrepo clone git@github.com:my/thing foo -b mybranch
|
||||
$ git subrepo pull foo
|
||||
$ git subrepo push foo
|
||||
|
||||
Collaborators see a file called 'foo/.gitrepo', and know that the subdir is a
|
||||
subrepo. The file contains all the information needed by future commands
|
||||
applied to that subrepo.
|
||||
|
||||
=head2 Git Subrepos
|
||||
|
||||
Now is a good time to dive into the techinical aspects of the C<subrepo>
|
||||
command, but first let me explain how it came about.
|
||||
|
||||
As you may have surmised by now, I am the author of git-subrepo. I'd used
|
||||
submodules on and off for years, and when I became aware of subtree I gave it
|
||||
a try, but I quickly realized its problems. I decided maybe it could be
|
||||
improved. I decided to write down my expected commandline usage and my ideals
|
||||
of what it would and would not do. Then I set off to implement it. It's been a
|
||||
long road, but what I ended up with was even better than what I wanted from
|
||||
the start.
|
||||
|
||||
Let's review the Goods and Bads:
|
||||
|
||||
Good:
|
||||
|
||||
=over
|
||||
|
||||
=item * Use an external repo in a dedicated subdir of your project.
|
||||
|
||||
=item * Pin the external repo to a specific commit.
|
||||
|
||||
=item * Users get everything with a normal clone command.
|
||||
|
||||
=item * Users don't need to know that subrepos are involved.
|
||||
|
||||
=item * Can use different submodules/commits per main project branch.
|
||||
|
||||
=item * Meta info is kept in an obvious place.
|
||||
|
||||
=item * Everyone knows when a subdir is a subrepo.
|
||||
|
||||
=item * Commandline UX is minimal and intuitive.
|
||||
|
||||
=item * Pulled history is always squashed out locally.
|
||||
|
||||
=item * Pushed history is kept intact.
|
||||
|
||||
=item * Creates a clean historical view. (See below)
|
||||
|
||||
=item * Bash code is very simple and easy to follow.
|
||||
|
||||
=item * Comprehensive test suite. Currently passing on travis:
|
||||
|
||||
=back
|
||||
|
||||
=for html
|
||||
<a href="https://travis-ci.org/ingydotnet/git-subrepo"><img src="https://travis-ci.org/ingydotnet/git-subrepo.png" alt="git-subrepo"></a>
|
||||
|
||||
Bad:
|
||||
|
||||
=over
|
||||
|
||||
=item * --Subrepo is very new.-- (no longer true)
|
||||
|
||||
=item * --Not well tested in the wild.-- (no longer true)
|
||||
|
||||
=back
|
||||
|
||||
This review may seem somewhat slanted, but I honestly am not aware of any
|
||||
"bad" points that I'm not disclosing. That said, I am sure time will reveal
|
||||
bugs and shortcomings. Those can usually be fixed. Hopefully the B<model> is
|
||||
correct, because that's harder to fix down the road.
|
||||
|
||||
OK. So how does it all work?
|
||||
|
||||
There are 3 main commands: cloneI<pull>push. Let's start with the clone
|
||||
command. This is the easiest part. You give it a remote url, possibly a new
|
||||
subdir to put it, and possibly a remote branch to use. I say possibly, because
|
||||
the command can guess the subdir name (just like the git-clone command does),
|
||||
and the branch can be the upstream default branch.
|
||||
|
||||
Given this we do the following steps internally:
|
||||
|
||||
=over
|
||||
|
||||
=item * Fetch the remote content (for a specific refspec)
|
||||
|
||||
=item * Read the remote head tree into the index
|
||||
|
||||
=item * Checkout the index into the new subdir
|
||||
|
||||
=item * Create a new subrepo commit object for the subdir content
|
||||
|
||||
=item * Add a state file called .gitrepo to the new subrepo/subdir
|
||||
|
||||
=item * Amend the merge commit with this new file
|
||||
|
||||
=back
|
||||
|
||||
This process adds something like this to the top of your history:
|
||||
|
||||
* 9b6ddc9 git subrepo clone git@github.com:you/foo.git foo/
|
||||
* 37c61a5 Previous head commit of your repo
|
||||
|
||||
The entire history has been squashed down into one commit, and placed on
|
||||
top of your history. This is important as it keeps your history as clean
|
||||
as possible. You don't need to have the subrepo history in your main
|
||||
project, since it is immutably available elsewhere, and you have a pointer
|
||||
to that place.
|
||||
|
||||
The new foo/.gitrepo file looks like this:
|
||||
|
||||
[subrepo]
|
||||
remote = git@github.com:you/foo.git
|
||||
branch = master
|
||||
commit = 14c96c6931b41257b2d42b2edc67ddc659325823
|
||||
parent = 37c61a5a234f5dd6f5c2aec037509f50d3a79b8f
|
||||
cmdver = 0.1.0
|
||||
|
||||
It contains all the info needed now and later. Note that the repo url is the
|
||||
generally pushable form, rather than the publically readable (L<https://…)>
|
||||
form. This is the best practice. Users of your repo don't need access to this
|
||||
url, because the content is already in your repo. Only you and your
|
||||
collaborators need this url to pull/push in the future.
|
||||
|
||||
The next command is the pull command. Normally you just give it the subrepo's
|
||||
subdir path (although you can change the branch with -b), and it will get the
|
||||
other info from the subdir/.gitrepo file.
|
||||
|
||||
The pull command does these steps:
|
||||
|
||||
=over
|
||||
|
||||
=item * Fetch the upstream content
|
||||
|
||||
=item * Check if anything needs pulling
|
||||
|
||||
=item * Create a branch of local subrepo commits since last pull
|
||||
|
||||
=item * Rebase this branch onto the upstream commits
|
||||
|
||||
=item * Commit the HEAD of the rebased content
|
||||
|
||||
=item * Update/amend the .gitrepo file
|
||||
|
||||
=back
|
||||
|
||||
=head3 Clean History
|
||||
|
||||
I've talked a bit about clean history but let me show you a comparison between
|
||||
subrepo and subtree. Let's run this command sequence using both methods. Note
|
||||
the differences between I<both> the command syntax required, and the branch
|
||||
history produced.
|
||||
|
||||
Subrepo first:
|
||||
|
||||
$ git subrepo clone git@github.com:user/abc
|
||||
$ git subrepo clone git@github.com:user/def xyz
|
||||
$ git subrepo pull abc
|
||||
$ git subrepo pull xyz
|
||||
|
||||
The resulting history is:
|
||||
|
||||
* b1f60cc subrepo pull xyz
|
||||
* 4fb0276 subrepo pull abc
|
||||
* bcef2a0 subrepo clone git@github.com:user/def xyz
|
||||
* bebf0db subrepo clone git@github.com:user/abc
|
||||
* 64eeaa6 (origin/master, origin/HEAD) O HAI FREND
|
||||
|
||||
Compare that to B<subtree>. This:
|
||||
|
||||
$ git subtree add abc git@github.com:user/abc master
|
||||
$ git subtree add xyz git@github.com:user/def master
|
||||
$ git subtree pull abc git@github.com:user/abc master
|
||||
$ git subtree pull xyz git@github.com:user/def master
|
||||
|
||||
Produces this:
|
||||
|
||||
* 739e45a (HEAD, master) Merge commit '5f563469d886d53e19cb908b3a64e4229f88a2d1'
|
||||
|\
|
||||
| * 5f56346 Squashed 'xyz/' changes from 08c7421..365409f
|
||||
* | 641f5e5 Merge commit '8d88e90ce5f653ed2e7608a71b8693a2174ea62a'
|
||||
|\ \
|
||||
| * | 8d88e90 Squashed 'abc/' changes from 08c7421..365409f
|
||||
* | | 1703ed2 Merge commit '0e091b672c4bbbbf6bc4f6694c475d127ffa21eb' as 'xyz'
|
||||
|\ \ \
|
||||
| | |/
|
||||
| |/|
|
||||
| * | 0e091b6 Squashed 'xyz/' content from commit 08c7421
|
||||
| /
|
||||
* | 07b77e7 Merge commit 'cd2b30a0229d931979ed4436b995875ec563faea' as 'abc'
|
||||
|\ \
|
||||
| |/
|
||||
| * cd2b30a Squashed 'abc/' content from commit 08c7421
|
||||
* 64eeaa6 (origin/master, origin/HEAD) O HAI FREND
|
||||
|
||||
This was from a minimal case. Subtree history (when viewed this way at least)
|
||||
gets unreasonably ugly fast. Subrepo history, by contrast, always looks as
|
||||
clean as shown.
|
||||
|
||||
The final command, push, bascially just does the pull/rebase dance above
|
||||
described, and pushes the resulting history back. It does not squash the
|
||||
commits made locally, because it assumed that when you changed the local
|
||||
subrepo, you made messages that were intended to eventually be published
|
||||
back upstream.
|
||||
|
||||
=head2 Conflict Resolution
|
||||
|
||||
The commands described above can also be done "by hand". If something fails
|
||||
during a pull or push (generally in the rebasing) then the command will tell
|
||||
you what to do to finish up.
|
||||
|
||||
You might choose to do everything by hand, and do your own merging strategies.
|
||||
This is perfectly reasonable. The C<subrepo> command offers a few other helper
|
||||
commands to help you get the job done:
|
||||
|
||||
=over
|
||||
|
||||
=item * C<fetch> - Fetch the upstream and create a C<< subrepo/remote/<subdir> >> ref.
|
||||
|
||||
=item * C<branch> - Create a branch of local subdir commits since the last pull, called C<< subrepo/<subdir> >>.
|
||||
|
||||
=item * C<commit> - Commit a merged branch's HEAD back into your repo.
|
||||
|
||||
=item * C<status> - Show lots of useful info about the current state of the subrepos.
|
||||
|
||||
=item * C<clean> - Remove branches, ref and remotes created by subrepo commands.
|
||||
|
||||
=item * C<help> - Read the complete documentation!
|
||||
|
||||
=back
|
||||
|
||||
=head2 Conclusion
|
||||
|
||||
Hopefully by now, you see that submodules are a painful choice with a dubious
|
||||
future, and that subtree, while a solid idea has many usage issues.
|
||||
|
||||
Give C<subrepo> a try. It's painless, easily revertable and just might be what
|
||||
the doctor ordered.
|
||||
|
||||
=head2 Reference Links
|
||||
|
||||
=over
|
||||
|
||||
=item * L<http://longair.net/blog/2010/06/02/git-submodules-explained/>
|
||||
|
||||
=item * L<http://blogs.atlassian.com/2013/05/alternatives-to-git-submodule-git-subtree/>
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
21
build/git-subrepo/License
Normal file
21
build/git-subrepo/License
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2020 Ingy döt Net
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
82
build/git-subrepo/Makefile
Normal file
82
build/git-subrepo/Makefile
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
# Make sure we have 'git' and it works OK:
|
||||
ifeq ($(shell which git),)
|
||||
$(error 'git' is not installed on this system)
|
||||
endif
|
||||
|
||||
# Set variables:
|
||||
NAME := git-subrepo
|
||||
LIB := lib/$(NAME)
|
||||
DOC := doc/$(NAME).swim
|
||||
MAN1 := man/man1
|
||||
EXT := $(LIB).d
|
||||
EXTS := $(shell find $(EXT) -type f) \
|
||||
$(shell find $(EXT) -type l)
|
||||
SHARE = share
|
||||
|
||||
# Install variables:
|
||||
PREFIX ?= /usr/local
|
||||
INSTALL_LIB ?= $(DESTDIR)$(shell git --exec-path)
|
||||
INSTALL_EXT ?= $(INSTALL_LIB)/$(NAME).d
|
||||
INSTALL_MAN1 ?= $(DESTDIR)$(PREFIX)/share/man/man1
|
||||
|
||||
# Basic targets:
|
||||
default: help
|
||||
|
||||
help:
|
||||
@echo 'Makefile rules:'
|
||||
@echo ''
|
||||
@echo 'test Run all tests'
|
||||
@echo 'install Install $(NAME)'
|
||||
@echo 'uninstall Uninstall $(NAME)'
|
||||
@echo 'env Show environment variables to set'
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
prove $(PROVEOPT:%=% )test/
|
||||
|
||||
# Install support:
|
||||
install:
|
||||
install -d -m 0755 $(INSTALL_LIB)/
|
||||
install -C -m 0755 $(LIB) $(INSTALL_LIB)/
|
||||
install -d -m 0755 $(INSTALL_EXT)/
|
||||
install -C -m 0755 $(EXTS) $(INSTALL_EXT)/
|
||||
install -d -m 0755 $(INSTALL_MAN1)/
|
||||
install -C -m 0644 $(MAN1)/$(NAME).1 $(INSTALL_MAN1)/
|
||||
|
||||
# Uninstall support:
|
||||
uninstall:
|
||||
rm -f $(INSTALL_LIB)/$(NAME)
|
||||
rm -fr $(INSTALL_EXT)
|
||||
rm -f $(INSTALL_MAN1)/$(NAME).1
|
||||
|
||||
env:
|
||||
@echo "export PATH=\"$$PWD/lib:\$$PATH\""
|
||||
@echo "export MANPATH=\"$$PWD/man:\$$MANPATH\""
|
||||
|
||||
# Doc rules:
|
||||
.PHONY: doc
|
||||
update: doc compgen
|
||||
|
||||
force:
|
||||
|
||||
doc: ReadMe.pod Intro.pod $(MAN1)/$(NAME).1
|
||||
perl pkg/bin/generate-help-functions.pl $(DOC) > \
|
||||
$(EXT)/help-functions.bash
|
||||
|
||||
ReadMe.pod: $(DOC) force
|
||||
swim --to=pod --wrap --complete $< > $@
|
||||
|
||||
Intro.pod: doc/intro-to-subrepo.swim force
|
||||
swim --to=pod --wrap --complete $< > $@
|
||||
|
||||
$(MAN1)/%.1: doc/%.swim Makefile force
|
||||
swim --to=man --wrap $< > $@
|
||||
|
||||
compgen: force
|
||||
perl pkg/bin/generate-completion.pl bash $(DOC) $(LIB) > \
|
||||
$(SHARE)/completion.bash
|
||||
perl pkg/bin/generate-completion.pl zsh $(DOC) $(LIB) > \
|
||||
$(SHARE)/zsh-completion/_git-subrepo
|
||||
|
||||
clean purge:
|
||||
rm -fr tmp
|
||||
28
build/git-subrepo/Meta
Normal file
28
build/git-subrepo/Meta
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
=meta: 0.0.2
|
||||
|
||||
name: git-subrepo
|
||||
version: 0.4.1
|
||||
abstract: Git Submodule Alternative
|
||||
homepage: https://github.com/ingydotnet/git-subrepo#readme
|
||||
license: MIT
|
||||
copyright: 2013-2020
|
||||
|
||||
author:
|
||||
name: Ingy döt Net
|
||||
email: ingy@ingy.net
|
||||
github: ingydotnet
|
||||
twitter: ingydotnet
|
||||
freenode: ingy
|
||||
homepage: http://ingy.net
|
||||
|
||||
requires:
|
||||
bash: 4.0.0
|
||||
git: 2.7.0
|
||||
test:
|
||||
cmd: make test
|
||||
install: make install
|
||||
|
||||
devel:
|
||||
git: git@github.org:ingydotnet/git-subrepo.git
|
||||
irc: irc.freenode.net/gitcommands
|
||||
bug: https://github.com/ingydotnet/git-subrepo/issues/
|
||||
698
build/git-subrepo/ReadMe.pod
Normal file
698
build/git-subrepo/ReadMe.pod
Normal file
|
|
@ -0,0 +1,698 @@
|
|||
=pod
|
||||
|
||||
=for comment
|
||||
DO NOT EDIT. This Pod was generated by Swim v0.1.48.
|
||||
See http://github.com/ingydotnet/swim-pm#readme
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 Name
|
||||
|
||||
git-subrepo - Git Submodule Alternative
|
||||
|
||||
=for html
|
||||
<a href="https://travis-ci.org/ingydotnet/git-subrepo"><img src="https://travis-ci.org/ingydotnet/git-subrepo.png" alt="git-subrepo"></a>
|
||||
|
||||
=head1 Synopsis
|
||||
|
||||
git subrepo -h # Help Overview
|
||||
|
||||
git subrepo clone <remote-url> [<subdir>]
|
||||
git subrepo init <subdir>
|
||||
git subrepo pull <subdir>
|
||||
git subrepo push <subdir>
|
||||
|
||||
git subrepo fetch <subdir>
|
||||
git subrepo branch <subdir>
|
||||
git subrepo commit <subdir>
|
||||
git subrepo config <subdir>
|
||||
|
||||
git subrepo status [<subdir>]
|
||||
git subrepo clean <subdir>
|
||||
|
||||
git subrepo help [<command> | --all]
|
||||
git subrepo version
|
||||
git subrepo upgrade
|
||||
|
||||
=head1 Description
|
||||
|
||||
This git command "clones" an external git repo into a subdirectory of your
|
||||
repo. Later on, upstream changes can be pulled in, and local changes can be
|
||||
pushed back. Simple.
|
||||
|
||||
=head1 Benefits
|
||||
|
||||
This command is an improvement from C<git-submodule> and C<git-subtree>; two
|
||||
other git commands with similar goals, but various problems.
|
||||
|
||||
It assumes there are 3 main roles of people interacting with a repo, and
|
||||
attempts to serve them all well:
|
||||
|
||||
=over
|
||||
|
||||
=item * B<owner> - The person who authors/owns/maintains a repo.
|
||||
|
||||
=item * B<users> - People who are just using/installing the repo.
|
||||
|
||||
=item * B<collaborators> - People who commit code to the repo and subrepos.
|
||||
|
||||
=back
|
||||
|
||||
The C<git-subrepo> command benefits these roles in the following ways:
|
||||
|
||||
=over
|
||||
|
||||
=item * Simple and intuitive commandline usage (with tab completion).
|
||||
|
||||
=item * Users get your repo and all your subrepos just by cloning your repo.
|
||||
|
||||
=item * Users do not need to install C<git-subrepo>, ever.
|
||||
|
||||
=item * Collaborators do not need to install unless they want to push/pull.
|
||||
|
||||
=item * Collaborators know when a subdir is a subrepo (it has a C<.gitrepo> file).
|
||||
|
||||
=item * The C<.gitrepo> file never gets pushed back to the subrepo upstream.
|
||||
|
||||
=item * Well named branches and remotes are generated for manual operations.
|
||||
|
||||
=item * Owners do not deal with the complications of keeping submodules in sync.
|
||||
|
||||
=item * Subrepo repositories can contain subrepos themselves.
|
||||
|
||||
=item * Branching with subrepos JustWorks™.
|
||||
|
||||
=item * Different branches can have different subrepos in different states, etc.
|
||||
|
||||
=item * Moving/renaming/deleting a subrepo subdir JustWorks™.
|
||||
|
||||
=item * You can C<init> an existing subdirectory into a subrepo.
|
||||
|
||||
=item * Your git history is kept squeaky clean.
|
||||
|
||||
=item * Upstream history (clone/pull) is condensed into a single commit.
|
||||
|
||||
=item * Pulls can use a C<merge>, C<rebase> or C<force> strategies.
|
||||
|
||||
=item * You can see the subrepo history with C<< git log subrepo/<subdir>/fetch >>.
|
||||
|
||||
=item * Commits pushed back upstream are B<not> condensed (by default).
|
||||
|
||||
=item * Trivial to try any subrepo operations and then reset back.
|
||||
|
||||
=item * No configuration required.
|
||||
|
||||
=item * Does not introduce history that messes up other git commands.
|
||||
|
||||
=item * Fixes known rebase failures with C<git-subtree>.
|
||||
|
||||
=back
|
||||
|
||||
=head1 Installation
|
||||
|
||||
The best short answer is:
|
||||
|
||||
git clone https://github.com/ingydotnet/git-subrepo /path/to/git-subrepo
|
||||
echo 'source /path/to/git-subrepo/.rc' >> ~/.bashrc
|
||||
|
||||
The complete "Installation Instructions" can be found below.
|
||||
|
||||
Note: git-subrepo needs a git version (> 2.7) that supports worktree:s.
|
||||
|
||||
=head1 Commands
|
||||
|
||||
All the B<subrepo> commands use names of actual Git commands and try to do
|
||||
operations that are similar to their Git counterparts. They also attempt to
|
||||
give similar output in an attempt to make the subrepo usage intuitive to
|
||||
experienced Git users.
|
||||
|
||||
Please note that the commands are I<not> exact equivalents, and do not take
|
||||
all the same arguments. Keep reading…
|
||||
|
||||
=over
|
||||
|
||||
=item C<< git subrepo clone <repository> [<subdir>] [-b <branch>] [-f] [-m <msg>] [-e] [--method <merge|rebase>] >>
|
||||
|
||||
Add a repository as a subrepo in a subdir of your repository.
|
||||
|
||||
This is similar in feel to C<git clone>. You just specify the remote repo url,
|
||||
and optionally a sub-directory and/or branch name. The repo will be fetched
|
||||
and merged into the subdir.
|
||||
|
||||
The subrepo history is I<squashed> into a single commit that contains the
|
||||
reference information. This information is also stored in a special file
|
||||
called C<< <subdir>/.gitrepo >>. The presence of this file indicates that the
|
||||
directory is a subrepo.
|
||||
|
||||
All subsequent commands refer to the subrepo by the name of the
|
||||
I<subdir>. From the subdir, all the current information about the subrepo
|
||||
can be obtained.
|
||||
|
||||
The C<--force> option will "reclone" (completely replace) an existing subdir.
|
||||
|
||||
The C<--method> option will decide how the join process between branches are
|
||||
performed. The default option is merge.
|
||||
|
||||
The C<clone> command accepts the C<--branch=> C<--edit>, C<--force> and C<--
|
||||
message=> options.
|
||||
|
||||
=item C<< git subrepo init <subdir> [-r <remote>] [-b <branch>] [--method <merge|rebase>] >>
|
||||
|
||||
Turn an existing subdirectory into a subrepo.
|
||||
|
||||
If you want to expose a subdirectory of your project as a published subrepo,
|
||||
this command will do that. It will split out the content of a normal
|
||||
subdirectory into a branch and start tracking it as a subrepo. Afterwards your
|
||||
original repo will look exactly the same except that there will be a C<<
|
||||
<subdir>/.gitrepo >> file.
|
||||
|
||||
If you specify the C<--remote> (and optionally the C<--branch>) option, the
|
||||
values will be added to the C<< <subdir>/.gitrepo >> file. The C<--remote>
|
||||
option is the upstream URL, and the C<--branch> option is the upstream branch
|
||||
to push to. These values will be needed to do a C<git subrepo push> command,
|
||||
but they can be provided later on the C<push> command (and saved to C<<
|
||||
<subdir>/.gitrepo >> if you also specify the C<--update> option).
|
||||
|
||||
Note: You will need to create the empty upstream repo and push to it on your
|
||||
own, using C<< git subrepo push <subdir> >>.
|
||||
|
||||
The C<--method> option will decide how the join process between branches are
|
||||
performed. The default option is merge.
|
||||
|
||||
The C<init> command accepts the C<--branch=> and C<--remote=> options.
|
||||
|
||||
=item C<< git subrepo pull <subdir>|--all [-M|-R|-f] [-m <msg>] [-e] [-b <branch>] [-r <remote>] [-u] >>
|
||||
|
||||
Update the subrepo subdir with the latest upstream changes.
|
||||
|
||||
The C<pull> command fetches the latest content from the remote branch pointed
|
||||
to by the subrepo's C<.gitrepo> file, and then tries to merge the changes into
|
||||
the corresponding subdir. It does this by making a branch of the local commits
|
||||
to the subdir and then merging or rebasing (see below) it with the fetched
|
||||
upstream content. After the merge, the content of the new branch replaces your
|
||||
subdir, the C<.gitrepo> file is updated and a single 'pull' commit is added to
|
||||
your mainline history.
|
||||
|
||||
The C<pull> command will attempt to do the following commands in one go:
|
||||
|
||||
git subrepo fetch <subdir>
|
||||
git subrepo branch <subdir>
|
||||
git merge/rebase subrepo/<subdir>/fetch subrepo/<subdir>
|
||||
git subrepo commit <subdir>
|
||||
# Only needed for a consequential push:
|
||||
git update-ref refs/subrepo/<subdir>/pull subrepo/<subdir>
|
||||
|
||||
In other words, you could do all the above commands yourself, for the same
|
||||
effect. If any of the commands fail, subrepo will stop and tell you to finish
|
||||
this by hand. Generally a failure would be in the merge or rebase part, where
|
||||
conflicts can happen. Since Git has lots of ways to resolve conflicts to your
|
||||
personal tastes, the subrepo command defers to letting you do this by hand.
|
||||
|
||||
When pulling new data, the method selected in clone/init is used. This has no
|
||||
effect on the final result of the pull, since it becomes a single commit. But
|
||||
it does affect the resulting C<< subrepo/<subdir> >> branch, which is often
|
||||
used for a subrepo C<push> command. See 'push' below for more information. If
|
||||
you want to change the method you can use the C<config> command for this.
|
||||
|
||||
When you pull you can assume a fast-forward strategy (default) or you can
|
||||
specify a C<--rebase>, C<--merge> or C<--force> strategy. The latter is the
|
||||
same as a C<clone --force> operation, using the current remote and branch.
|
||||
|
||||
Like the C<clone> command, C<pull> will squash all the changes (since the last
|
||||
pull or clone) into one commit. This keeps your mainline history nice and
|
||||
clean. You can easily see the subrepo's history with the C<git log> command:
|
||||
|
||||
git log refs/subrepo/<subdir>/fetch
|
||||
|
||||
The set of commands used above are described in detail below.
|
||||
|
||||
The C<pull> command accepts the C<--all>, C<--branch=>, C<--edit>, C<--force>,
|
||||
C<--message=>, C<--remote=> and C<--update> options.
|
||||
|
||||
=item C<< git subrepo push <subdir>|--all [<branch>] [-r <remote>] [-b <branch>] [-M|-R] [-u] [-f] [-s] [-N] >>
|
||||
|
||||
Push a properly merged subrepo branch back upstream.
|
||||
|
||||
This command takes the subrepo branch from a successful pull command and
|
||||
pushes the history back to its designated remote and branch. You can also use
|
||||
the C<branch> command and merge things yourself before pushing if you want to
|
||||
(although that is probably a rare use case).
|
||||
|
||||
The C<push> command requires a branch that has been properly merged/rebased
|
||||
with the upstream HEAD (unless the upstream HEAD is empty, which is common
|
||||
when doing a first C<push> after an C<init>). That means the upstream HEAD is
|
||||
one of the commits in the branch.
|
||||
|
||||
By default the branch ref C<< refs/subrepo/<subdir>/pull >> will be pushed,
|
||||
but you can specify a (properly merged) branch to push.
|
||||
|
||||
After that, the C<push> command just checks that the branch contains the
|
||||
upstream HEAD and then pushes it upstream.
|
||||
|
||||
The C<--force> option will do a force push. Force pushes are typically
|
||||
discouraged. Only use this option if you fully understand it. (The C<--force>
|
||||
option will NOT check for a proper merge. ANY branch will be force pushed!)
|
||||
|
||||
The C<push> command accepts the C<--all>, C<--branch=>, C<--dry-run>, C<--
|
||||
force>, C<--merge>, C<--rebase>, C<--remote=>, C<--squash> and C<--
|
||||
update> options.
|
||||
|
||||
=item C<< git subrepo fetch <subdir>|--all [-r <remote>] [-b <branch>] >>
|
||||
|
||||
Fetch the remote/upstream content for a subrepo.
|
||||
|
||||
It will create a Git reference called C<< subrepo/<subdir>/fetch >> that
|
||||
points at the same commit as C<FETCH_HEAD>. It will also create a remote
|
||||
called C<< subrepo/<subdir> >>. These are temporary and you can easily remove
|
||||
them with the subrepo C<clean> command.
|
||||
|
||||
The C<fetch> command accepts the C<--all>, C<--branch=> and C<--
|
||||
remote=> options.
|
||||
|
||||
=item C<< git subrepo branch <subdir>|--all [-f] [-F] >>
|
||||
|
||||
Create a branch with local subrepo commits.
|
||||
|
||||
Scan the history of the mainline for all the commits that affect the C<subdir>
|
||||
and create a new branch from them called C<< subrepo/<subdir> >>.
|
||||
|
||||
This is useful for doing C<pull> and C<push> commands by hand.
|
||||
|
||||
Use the C<--force> option to write over an existing C<< subrepo/<subdir>
|
||||
>> branch.
|
||||
|
||||
The C<branch> command accepts the C<--all>, C<--fetch> and C<--force> options.
|
||||
|
||||
=item C<< git subrepo commit <subdir> [<subrepo-ref>] [-m <msg>] [-e] [-f] [-F] >>
|
||||
|
||||
Add subrepo branch to current history as a single commit.
|
||||
|
||||
This command is generally used after a hand-merge. You have done a C<subrepo
|
||||
branch> and merged (rebased) it with the upstream. This command takes the HEAD
|
||||
of that branch, puts its content into the subrepo subdir and adds a new commit
|
||||
for it to the top of your mainline history.
|
||||
|
||||
This command requires that the upstream HEAD be in the C<< subrepo/<subdir> >>
|
||||
branch history. That way the same branch can push upstream. Use the C<--force>
|
||||
option to commit anyway.
|
||||
|
||||
The C<commit> command accepts the C<--edit>, C<--fetch>, C<--force> and C<--
|
||||
message=> options.
|
||||
|
||||
=item C<< git subrepo status [<subdir>|--all|--ALL] [-F] [-q|-v] >>
|
||||
|
||||
Get the status of a subrepo. Uses the C<--all> option by default. If the C<--
|
||||
quiet> flag is used, just print the subrepo names, one per line.
|
||||
|
||||
The C<--verbose> option will show all the recent local and upstream commits.
|
||||
|
||||
Use C<--ALL> to show the subrepos of the subrepos (ie the
|
||||
"subsubrepos"), if any.
|
||||
|
||||
The C<status> command accepts the C<--all>, C<--ALL>, C<--fetch>, C<--quiet>
|
||||
and C<--verbose> options.
|
||||
|
||||
=item C<< git subrepo clean <subdir>|--all|--ALL [-f] >>
|
||||
|
||||
Remove artifacts created by C<fetch> and C<branch> commands.
|
||||
|
||||
The C<fetch> and C<branch> operations (and other commands that call them)
|
||||
create temporary things like refs, branches and remotes. This command removes
|
||||
all those things.
|
||||
|
||||
Use C<--force> to remove refs. Refs are not removed by default because they
|
||||
are sometimes needed between commands.
|
||||
|
||||
Use C<--all> to clean up after all the current subrepos. Sometimes you might
|
||||
change to a branch where a subrepo doesn't exist, and then C<--all> won't find
|
||||
it. Use C<--ALL> to remove any artifacts that were ever created by subrepo.
|
||||
|
||||
To remove ALL subrepo artifacts:
|
||||
|
||||
git subrepo clean --ALL --force
|
||||
|
||||
The C<clean> command accepts the C<--all>, C<--ALL>, and C<--force> options.
|
||||
|
||||
=item C<< git subrepo config <subdir> <option> [<value>] [-f] >>
|
||||
|
||||
Read or update configuration values in the subdir/.gitrepo file.
|
||||
|
||||
Because most of the values stored in the .gitrepo file are generated you
|
||||
will need to use C<--force> if you want to change anything else then the
|
||||
C<method> option.
|
||||
|
||||
Example to update the C<method> option for a subrepo:
|
||||
|
||||
git subrepo config foo method rebase
|
||||
|
||||
=item C<< git subrepo help [<command>|--all] >>
|
||||
|
||||
Same as C<git help subrepo>. Will launch the manpage. For the shorter usage,
|
||||
use C<git subrepo -h>.
|
||||
|
||||
Use C<< git subrepo help <command> >> to get help for a specific command. Use
|
||||
C<--all> to get a summary of all commands.
|
||||
|
||||
The C<help> command accepts the C<--all> option.
|
||||
|
||||
=item C<git subrepo version [-q|-v]>
|
||||
|
||||
This command will display version information about git-subrepo and its
|
||||
environment. For just the version number, use C<git subrepo --version>. Use
|
||||
C<--verbose> for more version info, and C<--quiet> for less.
|
||||
|
||||
The C<version> command accepts the C<--quiet> and C<--verbose> options.
|
||||
|
||||
=item C<git subrepo upgrade>
|
||||
|
||||
Upgrade the C<git-subrepo> software itself. This simply does a C<git pull>
|
||||
on the git repository that the code is running from. It only works if you
|
||||
are on the C<master> branch. It won't work if you installed C<git-subrepo>
|
||||
using C<make install>; in that case you'll need to C<make install> from the
|
||||
latest code.
|
||||
|
||||
=back
|
||||
|
||||
=head1 Command Options
|
||||
|
||||
=over
|
||||
|
||||
=item C<-h>
|
||||
|
||||
Show a brief view of the commands and options.
|
||||
|
||||
=item C<--help>
|
||||
|
||||
Gives an overview of the help options available for the subrepo command.
|
||||
|
||||
=item C<--version>
|
||||
|
||||
Print the git-subrepo version. Just the version number. Try the C<version>
|
||||
command for more version info.
|
||||
|
||||
=item C<--all> (C<-a>)
|
||||
|
||||
If you have multiple subrepos, issue the command to all of them (if
|
||||
applicable).
|
||||
|
||||
=item C<--ALL> (C<-A>)
|
||||
|
||||
If you have subrepos that also have subrepos themselves, issue the command to
|
||||
ALL of them. Note that the C<--ALL> option only works for a subset of the
|
||||
commands that C<--all> works for.
|
||||
|
||||
=item C<< --branch=<branch-name> >> (C<< -b <branch-name> >>)
|
||||
|
||||
Use a different upstream branch-name than the remote HEAD or the one saved in
|
||||
C<.gitrepo> locally.
|
||||
|
||||
=item C<--dry-run> (C<-N>)
|
||||
|
||||
For the push command, do everything up until the push and then print out the
|
||||
actual C<git push> command needed to finish the operation.
|
||||
|
||||
=item C<--edit> (C<-e>)
|
||||
|
||||
Edit the commit message before committing.
|
||||
|
||||
=item C<--fetch> (C<-F>)
|
||||
|
||||
Use this option to fetch the upstream commits, before running the command.
|
||||
|
||||
=item C<--force> (C<-f>)
|
||||
|
||||
Use this option to force certain commands that fail in the general case.
|
||||
|
||||
NOTE: The C<--force> option means different things for different commands.
|
||||
Read the command specific doc for the exact meaning.
|
||||
|
||||
=item C<--merge> (C<-M>)
|
||||
|
||||
Use a C<merge> strategy to include upstream subrepo commits on a pull (or
|
||||
setup for push).
|
||||
|
||||
=item C<< --message=<message> >> (C<< -m <message> >>)
|
||||
|
||||
Specify your own commit message on the command line.
|
||||
|
||||
=item C<--rebase> (C<-R>)
|
||||
|
||||
Use a C<rebase> strategy to include upstream subrepo commits on a pull (or
|
||||
setup for push).
|
||||
|
||||
=item C<< --remote=<remote-url> >> (C<< -r <remote-url> >>)
|
||||
|
||||
Use a different remote-url than the one saved in C<.gitrepo> locally.
|
||||
|
||||
=item C<--squash> (C<-s>)
|
||||
|
||||
Squash all commits on a push into one new commit.
|
||||
|
||||
=item C<--update> (C<-u>)
|
||||
|
||||
If C<--branch> or C<--remote> are used, and the command updates the
|
||||
C<.gitrepo> file, include these values to the update.
|
||||
|
||||
=back
|
||||
|
||||
=head1 Output Options
|
||||
|
||||
=over
|
||||
|
||||
=item C<--quiet> (C<-q>)
|
||||
|
||||
Print as little info as possible. Applicable to most commands.
|
||||
|
||||
=item C<--verbose> (C<-v>)
|
||||
|
||||
Print more information about the command execution and results. Applicable to
|
||||
most commands.
|
||||
|
||||
=item C<--debug> (C<-d>)
|
||||
|
||||
Show the actual git (and other) commands being executed under the hood.
|
||||
Applicable to most commands.
|
||||
|
||||
=item C<--DEBUG> (C<-x>)
|
||||
|
||||
Use the Bash C<set -x> option which prints every command before it is
|
||||
run. VERY noisy, but extremely useful in deep debugging. Applicable to
|
||||
all commands.
|
||||
|
||||
=back
|
||||
|
||||
=head1 Environment Variables
|
||||
|
||||
The C<git-subrepo> command exports and honors some environment variables:
|
||||
|
||||
=over
|
||||
|
||||
=item C<GIT_SUBREPO_ROOT>
|
||||
|
||||
This is set by the C<.rc> file, if you use that method to install / enable C<git-
|
||||
subrepo>. It contains the path of the C<git-subrepo> repository.
|
||||
|
||||
=item C<GIT_SUBREPO_RUNNING>
|
||||
|
||||
This variable is exported when C<git-subrepo> is running. It is set to the pid
|
||||
of the C<git-subrepo> process that is running. Other processes, like git hooks
|
||||
for instance, can use this information to adjust accordingly.
|
||||
|
||||
=item C<GIT_SUBREPO_COMMAND>
|
||||
|
||||
This variable is exported when C<git-subrepo> is running. It is set to the
|
||||
name of the C<git-subrepo> subcommand that is running.
|
||||
|
||||
=item C<GIT_SUBREPO_PAGER>
|
||||
|
||||
Use this to specify the pager to use for long output commands. Defaults to
|
||||
C<$PAGER> or C<less>.
|
||||
|
||||
=item C<GIT_SUBREPO_QUIET>
|
||||
|
||||
Set this for quiet (C<-q>) output.
|
||||
|
||||
=item C<GIT_SUBREPO_VERBOSE>
|
||||
|
||||
Set this for verbose (C<-v>) output.
|
||||
|
||||
=item C<GIT_SUBREPO_DEBUG>
|
||||
|
||||
Set this for debugging (C<-d>) output.
|
||||
|
||||
=back
|
||||
|
||||
=head1 Installation Instructions
|
||||
|
||||
There are currently 3 ways to install C<git-subrepo>. For all of them you need
|
||||
to get the source code from GitHub:
|
||||
|
||||
git clone https://github.com/ingydotnet/git-subrepo /path/to/git-subrepo
|
||||
|
||||
The first installation method is preferred: C<source> the C<.rc> file. Just
|
||||
add a line like this one to your shell startup script:
|
||||
|
||||
source /path/to/git-subrepo/.rc
|
||||
|
||||
That will modify your C<PATH> and C<MANPATH>, and also enable command
|
||||
completion.
|
||||
|
||||
The second method is to do these things by hand. This might afford you more
|
||||
control of your shell environment. Simply add the C<lib> and C<man>
|
||||
directories to your C<PATH> and C<MANPATH>:
|
||||
|
||||
export GIT_SUBREPO_ROOT="/path/to/git-subrepo"
|
||||
export PATH="/path/to/git-subrepo/lib:$PATH"
|
||||
export MANPATH="/path/to/git-subrepo/man:$MANPATH"
|
||||
|
||||
See below for info on how to turn on Command Completion.
|
||||
|
||||
The third method is a standard system install, which puts C<git-subrepo> next
|
||||
to your other git commands:
|
||||
|
||||
make install # Possibly with 'sudo'
|
||||
|
||||
This method does not account for upgrading and command completion yet.
|
||||
|
||||
=head2 Windows
|
||||
|
||||
This command is known to work in these Windows environments:
|
||||
|
||||
=over
|
||||
|
||||
=item * Git for Windows -- L<https://git-for-windows.github.io/>
|
||||
|
||||
=item * Babun -- L<http://babun.github.io/>
|
||||
|
||||
=item * Cygwin -- L<https://www.cygwin.com/>
|
||||
|
||||
=back
|
||||
|
||||
Let us know if there are others that it works (or doesn't work) in.
|
||||
|
||||
=head1 Testing
|
||||
|
||||
The C<git-subrepo> repository comes with a extensive test suite. You can
|
||||
run it with:
|
||||
|
||||
make test
|
||||
|
||||
or if you don't have C<make> on your system:
|
||||
|
||||
prove -v test
|
||||
|
||||
=head1 Upgrading
|
||||
|
||||
If you used the C<.rc> or C<PATH> method of installation, just run this to
|
||||
upgrade C<git-subrepo>:
|
||||
|
||||
git subrepo upgrade
|
||||
|
||||
Or (same thing):
|
||||
|
||||
cd /path/to/git-subrepo
|
||||
git pull
|
||||
|
||||
If you used C<make install> method, then run this again (after C<git pull>):
|
||||
|
||||
make install # Possibly with 'sudo'
|
||||
|
||||
=head1 Command Completion
|
||||
|
||||
The C<git subrepo> command supports C<< <TAB> >>-based command completion. If
|
||||
you don't use the C<.rc> script (see Installation, above), you'll need to
|
||||
enable this manually to use it.
|
||||
|
||||
=head2 In Bash
|
||||
|
||||
If your Bash setup does not already provide command completion for Git, you'll
|
||||
need to enable that first:
|
||||
|
||||
source <Git completion script>
|
||||
|
||||
On your system, the Git completion script might be found at any of the
|
||||
following locations (or somewhere else that we don't know about):
|
||||
|
||||
=over
|
||||
|
||||
=item * C</etc/bash_completion.d/git>
|
||||
|
||||
=item * C</usr/share/bash-completion/git>
|
||||
|
||||
=item * C</usr/share/bash-completion/completions/git>
|
||||
|
||||
=item * C</opt/local/share/bash-completion/completions/git>
|
||||
|
||||
=item * C</usr/local/etc/bash_completion.d/git>
|
||||
|
||||
=item * C<~/.homebrew/etc/bash_completion.d/git>
|
||||
|
||||
=back
|
||||
|
||||
In case you can't find any of these, this repository contains a copy of the
|
||||
Git completion script:
|
||||
|
||||
source /path/to/git-subrepo/share/git-completion.bash
|
||||
|
||||
Once Git completion is enabled (whether you needed to do that manually or
|
||||
not), you can turn on C<git-subrepo> completion with a command like this:
|
||||
|
||||
source /path/to/git-subrepo/share/completion.bash
|
||||
|
||||
=head2 In zsh
|
||||
|
||||
In the Z shell (zsh), you can manually enable C<git-subrepo> completion by
|
||||
adding the following line to your C<~/.zshrc>, B<before> the C<compinit>
|
||||
function is called:
|
||||
|
||||
fpath=('/path/to/git-subrepo/share/zsh-completion' $fpath)
|
||||
|
||||
=head1 Status
|
||||
|
||||
The git-subrepo command has been in use for well over a year and seems to get
|
||||
the job done. Development is still ongoing but mostly just for fixing bugs.
|
||||
|
||||
Trying subrepo out is simple and painless (this is not C<git submodule>).
|
||||
Nothing is permanent (if you do not push to shared remotes). ie You can always
|
||||
play around and reset back to the beginning without pain.
|
||||
|
||||
This command has a test suite (run C<make test>), but surely has many bugs. If
|
||||
you have expertise with Git and subcommands, please review the code, and file
|
||||
issues on anything that seems wrong.
|
||||
|
||||
If you want to chat about the C<git-subrepo> command, join C<#gitcommands> on
|
||||
C<irc.freenode.net>.
|
||||
|
||||
=head1 Notes
|
||||
|
||||
=over
|
||||
|
||||
=item * Works on POSIX systems: Linux, BSD, OSX, etc.
|
||||
|
||||
=item * Works on various Windows environments. See "Windows" section above.
|
||||
|
||||
=item * The C<git-subrepo> repo itself has 2 subrepos under the C<ext/> subdirectory.
|
||||
|
||||
=item * Written in (very modern) Bash, with full test suite. Take a look.
|
||||
|
||||
=item * A C<.gitrepo> file never is in the top level dir (next to a C<.git/> dir).
|
||||
|
||||
=back
|
||||
|
||||
=head1 Authors
|
||||
|
||||
=over
|
||||
|
||||
=item * Ingy döt Net <ingy@ingy.net>
|
||||
|
||||
=item * Magnus Carlsson <grimmymail@gmail.com>
|
||||
|
||||
=back
|
||||
|
||||
=head1 License and Copyright
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2020 Ingy döt Net
|
||||
|
||||
=cut
|
||||
35
build/git-subrepo/doc/comparison.swim
Normal file
35
build/git-subrepo/doc/comparison.swim
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
= Comparing `submodule` and `subrepo`
|
||||
|
||||
This document compares Git's `submodule` command to the new `subrepo` command,
|
||||
with examples and discussion of all the common operations. I'll use the term
|
||||
"External" to mean the general concept of an external repo that might be used
|
||||
as a submodule or a subrepo.
|
||||
|
||||
= Overview
|
||||
|
||||
|
||||
|
||||
= Adding a new External
|
||||
|
||||
As an owner or collaborator, you have decided to add a new External to your
|
||||
repo:
|
||||
|
||||
- Submodule :: `git submodule add git@github.com/user/external`
|
||||
- Subtree :: `git subtree --squash --prefix=external git@github.com/user/external`
|
||||
- Subrepo :: `git subrepo clone git@github.com/user/external`
|
||||
|
||||
/…to be completed…/
|
||||
|
||||
= Updating from a changed External
|
||||
|
||||
= Pushing External changes upstream
|
||||
|
||||
= Moving/Renaming an External
|
||||
|
||||
= Making an External on a branch
|
||||
|
||||
= Changing the tracking branch of an External
|
||||
|
||||
= Removing an External
|
||||
|
||||
= Migration from One to the Other
|
||||
608
build/git-subrepo/doc/git-subrepo.swim
Normal file
608
build/git-subrepo/doc/git-subrepo.swim
Normal file
|
|
@ -0,0 +1,608 @@
|
|||
git-subrepo
|
||||
===========
|
||||
|
||||
Git Submodule Alternative
|
||||
|
||||
<badge travis ingydotnet/git-subrepo>
|
||||
|
||||
= Synopsis
|
||||
|
||||
git subrepo -h # Help Overview
|
||||
|
||||
git subrepo clone <remote-url> [<subdir>]
|
||||
git subrepo init <subdir>
|
||||
git subrepo pull <subdir>
|
||||
git subrepo push <subdir>
|
||||
|
||||
git subrepo fetch <subdir>
|
||||
git subrepo branch <subdir>
|
||||
git subrepo commit <subdir>
|
||||
git subrepo config <subdir>
|
||||
|
||||
git subrepo status [<subdir>]
|
||||
git subrepo clean <subdir>
|
||||
|
||||
git subrepo help [<command> | --all]
|
||||
git subrepo version
|
||||
git subrepo upgrade
|
||||
|
||||
= Description
|
||||
|
||||
This git command "clones" an external git repo into a subdirectory of your
|
||||
repo. Later on, upstream changes can be pulled in, and local changes can be
|
||||
pushed back. Simple.
|
||||
|
||||
= Benefits
|
||||
|
||||
This command is an improvement from `git-submodule` and `git-subtree`; two
|
||||
other git commands with similar goals, but various problems.
|
||||
|
||||
It assumes there are 3 main roles of people interacting with a repo, and
|
||||
attempts to serve them all well:
|
||||
|
||||
* *owner* - The person who authors\/owns\/maintains a repo.
|
||||
* *users* - People who are just using/installing the repo.
|
||||
* *collaborators* - People who commit code to the repo and subrepos.
|
||||
|
||||
The `git-subrepo` command benefits these roles in the following ways:
|
||||
|
||||
* Simple and intuitive commandline usage (with tab completion).
|
||||
* Users get your repo and all your subrepos just by cloning your repo.
|
||||
* Users do not need to install `git-subrepo`, ever.
|
||||
* Collaborators do not need to install unless they want to push/pull.
|
||||
* Collaborators know when a subdir is a subrepo (it has a `.gitrepo` file).
|
||||
* The `.gitrepo` file never gets pushed back to the subrepo upstream.
|
||||
* Well named branches and remotes are generated for manual operations.
|
||||
* Owners do not deal with the complications of keeping submodules in sync.
|
||||
* Subrepo repositories can contain subrepos themselves.
|
||||
* Branching with subrepos JustWorks™.
|
||||
* Different branches can have different subrepos in different states, etc.
|
||||
* Moving\/renaming\/deleting a subrepo subdir JustWorks™.
|
||||
* You can `init` an existing subdirectory into a subrepo.
|
||||
* Your git history is kept squeaky clean.
|
||||
* Upstream history (clone/pull) is condensed into a single commit.
|
||||
* Pulls can use a `merge`, `rebase` or `force` strategies.
|
||||
* You can see the subrepo history with `git log subrepo/<subdir>/fetch`.
|
||||
* Commits pushed back upstream are *not* condensed (by default).
|
||||
* Trivial to try any subrepo operations and then reset back.
|
||||
* No configuration required.
|
||||
* Does not introduce history that messes up other git commands.
|
||||
* Fixes known rebase failures with `git-subtree`.
|
||||
|
||||
= Installation
|
||||
|
||||
The best short answer is:
|
||||
|
||||
git clone https://github.com/ingydotnet/git-subrepo /path/to/git-subrepo
|
||||
echo 'source /path/to/git-subrepo/.rc' >> ~/.bashrc
|
||||
|
||||
The complete "Installation Instructions" can be found below.
|
||||
|
||||
Note: git-subrepo needs a git version (> 2.7) that supports worktree:s.
|
||||
|
||||
= Commands
|
||||
|
||||
All the *subrepo* commands use names of actual Git commands and try to do
|
||||
operations that are similar to their Git counterparts. They also attempt to
|
||||
give similar output in an attempt to make the subrepo usage intuitive to
|
||||
experienced Git users.
|
||||
|
||||
Please note that the commands are /not/ exact equivalents, and do not take all
|
||||
the same arguments. Keep reading…
|
||||
|
||||
- `git subrepo clone <repository> [<subdir>] [-b <branch>] [-f] [-m <msg>] [-e] [--method <merge|rebase>]`
|
||||
|
||||
Add a repository as a subrepo in a subdir of your repository.
|
||||
|
||||
This is similar in feel to `git clone`. You just specify the remote repo
|
||||
url, and optionally a sub-directory and/or branch name. The repo will be
|
||||
fetched and merged into the subdir.
|
||||
|
||||
The subrepo history is /squashed/ into a single commit that contains the
|
||||
reference information. This information is also stored in a special file
|
||||
called `<subdir>/.gitrepo`. The presence of this file indicates that the
|
||||
directory is a subrepo.
|
||||
|
||||
All subsequent commands refer to the subrepo by the name of the /subdir/.
|
||||
From the subdir, all the current information about the subrepo can be
|
||||
obtained.
|
||||
|
||||
The `--force` option will "reclone" (completely replace) an existing subdir.
|
||||
|
||||
The `--method` option will decide how the join process between branches are
|
||||
performed. The default option is merge.
|
||||
|
||||
The `clone` command accepts the `--branch=` `--edit`, `--force` and
|
||||
`--message=` options.
|
||||
|
||||
- `git subrepo init <subdir> [-r <remote>] [-b <branch>] [--method <merge|rebase>]`
|
||||
|
||||
Turn an existing subdirectory into a subrepo.
|
||||
|
||||
If you want to expose a subdirectory of your project as a published subrepo,
|
||||
this command will do that. It will split out the content of a normal
|
||||
subdirectory into a branch and start tracking it as a subrepo. Afterwards
|
||||
your original repo will look exactly the same except that there will be a
|
||||
`<subdir>/.gitrepo` file.
|
||||
|
||||
If you specify the `--remote` (and optionally the `--branch`) option, the
|
||||
values will be added to the `<subdir>/.gitrepo` file. The `--remote` option
|
||||
is the upstream URL, and the `--branch` option is the upstream branch to push
|
||||
to. These values will be needed to do a `git subrepo push` command, but they
|
||||
can be provided later on the `push` command (and saved to `<subdir>/.gitrepo`
|
||||
if you also specify the `--update` option).
|
||||
|
||||
Note: You will need to create the empty upstream repo and push to it on your
|
||||
own, using `git subrepo push <subdir>`.
|
||||
|
||||
The `--method` option will decide how the join process between branches
|
||||
are performed. The default option is merge.
|
||||
|
||||
The `init` command accepts the `--branch=` and `--remote=` options.
|
||||
|
||||
- `git subrepo pull <subdir>|--all [-M|-R|-f] [-m <msg>] [-e] [-b <branch>] [-r <remote>] [-u]`
|
||||
|
||||
Update the subrepo subdir with the latest upstream changes.
|
||||
|
||||
The `pull` command fetches the latest content from the remote branch pointed
|
||||
to by the subrepo's `.gitrepo` file, and then tries to merge the changes into
|
||||
the corresponding subdir. It does this by making a branch of the local
|
||||
commits to the subdir and then merging or rebasing (see below) it with the
|
||||
fetched upstream content. After the merge, the content of the new branch
|
||||
replaces your subdir, the `.gitrepo` file is updated and a single 'pull'
|
||||
commit is added to your mainline history.
|
||||
|
||||
The `pull` command will attempt to do the following commands in one go:
|
||||
|
||||
git subrepo fetch <subdir>
|
||||
git subrepo branch <subdir>
|
||||
git merge/rebase subrepo/<subdir>/fetch subrepo/<subdir>
|
||||
git subrepo commit <subdir>
|
||||
# Only needed for a consequential push:
|
||||
git update-ref refs/subrepo/<subdir>/pull subrepo/<subdir>
|
||||
|
||||
In other words, you could do all the above commands yourself, for the same
|
||||
effect. If any of the commands fail, subrepo will stop and tell you to finish
|
||||
this by hand. Generally a failure would be in the merge or rebase part, where
|
||||
conflicts can happen. Since Git has lots of ways to resolve conflicts to your
|
||||
personal tastes, the subrepo command defers to letting you do this by hand.
|
||||
|
||||
When pulling new data, the method selected in clone/init is used. This has
|
||||
no effect on the final result of the pull, since it becomes a single commit.
|
||||
But it does affect the resulting `subrepo/<subdir>` branch, which is often
|
||||
used for a subrepo `push` command. See 'push' below for more information.
|
||||
If you want to change the method you can use the `config` command for this.
|
||||
|
||||
When you pull you can assume a fast-forward strategy (default) or you can
|
||||
specify a `--rebase`, `--merge` or `--force` strategy. The latter is the same
|
||||
as a `clone --force` operation, using the current remote and branch.
|
||||
|
||||
Like the `clone` command, `pull` will squash all the changes (since the last
|
||||
pull or clone) into one commit. This keeps your mainline history nice and
|
||||
clean. You can easily see the subrepo's history with the `git log` command:
|
||||
|
||||
git log refs/subrepo/<subdir>/fetch
|
||||
|
||||
The set of commands used above are described in detail below.
|
||||
|
||||
The `pull` command accepts the `--all`, `--branch=`, `--edit`, `--force`,
|
||||
`--message=`, `--remote=` and `--update` options.
|
||||
|
||||
- `git subrepo push <subdir>|--all [<branch>] [-r <remote>] [-b <branch>] [-M|-R] [-u] [-f] [-s] [-N]`
|
||||
|
||||
Push a properly merged subrepo branch back upstream.
|
||||
|
||||
This command takes the subrepo branch from a successful pull command and
|
||||
pushes the history back to its designated remote and branch. You can also use
|
||||
the `branch` command and merge things yourself before pushing if you want to
|
||||
(although that is probably a rare use case).
|
||||
|
||||
The `push` command requires a branch that has been properly merged/rebased
|
||||
with the upstream HEAD (unless the upstream HEAD is empty, which is common
|
||||
when doing a first `push` after an `init`). That means the upstream HEAD is
|
||||
one of the commits in the branch.
|
||||
|
||||
By default the branch ref `refs/subrepo/<subdir>/pull` will be pushed, but
|
||||
you can specify a (properly merged) branch to push.
|
||||
|
||||
After that, the `push` command just checks that the branch contains the
|
||||
upstream HEAD and then pushes it upstream.
|
||||
|
||||
The `--force` option will do a force push. Force pushes are typically
|
||||
discouraged. Only use this option if you fully understand it. (The `--force`
|
||||
option will NOT check for a proper merge. ANY branch will be force pushed!)
|
||||
|
||||
The `push` command accepts the `--all`, `--branch=`, `--dry-run`, `--force`,
|
||||
`--merge`, `--rebase`, `--remote=`, `--squash` and `--update` options.
|
||||
|
||||
- `git subrepo fetch <subdir>|--all [-r <remote>] [-b <branch>]`
|
||||
|
||||
Fetch the remote/upstream content for a subrepo.
|
||||
|
||||
It will create a Git reference called `subrepo/<subdir>/fetch` that points at
|
||||
the same commit as `FETCH_HEAD`. It will also create a remote called
|
||||
`subrepo/<subdir>`. These are temporary and you can easily remove them with
|
||||
the subrepo `clean` command.
|
||||
|
||||
The `fetch` command accepts the `--all`, `--branch=` and `--remote=` options.
|
||||
|
||||
- `git subrepo branch <subdir>|--all [-f] [-F]`
|
||||
|
||||
Create a branch with local subrepo commits.
|
||||
|
||||
Scan the history of the mainline for all the commits that affect the `subdir`
|
||||
and create a new branch from them called `subrepo/<subdir>`.
|
||||
|
||||
This is useful for doing `pull` and `push` commands by hand.
|
||||
|
||||
Use the `--force` option to write over an existing `subrepo/<subdir>` branch.
|
||||
|
||||
The `branch` command accepts the `--all`, `--fetch` and `--force` options.
|
||||
|
||||
- `git subrepo commit <subdir> [<subrepo-ref>] [-m <msg>] [-e] [-f] [-F]`
|
||||
|
||||
Add subrepo branch to current history as a single commit.
|
||||
|
||||
This command is generally used after a hand-merge. You have done a `subrepo
|
||||
branch` and merged (rebased) it with the upstream. This command takes the
|
||||
HEAD of that branch, puts its content into the subrepo subdir and adds a new
|
||||
commit for it to the top of your mainline history.
|
||||
|
||||
This command requires that the upstream HEAD be in the `subrepo/<subdir>`
|
||||
branch history. That way the same branch can push upstream. Use the
|
||||
`--force` option to commit anyway.
|
||||
|
||||
The `commit` command accepts the `--edit`, `--fetch`, `--force` and
|
||||
`--message=` options.
|
||||
|
||||
- `git subrepo status [<subdir>|--all|--ALL] [-F] [-q|-v]`
|
||||
|
||||
Get the status of a subrepo. Uses the `--all` option by default. If the
|
||||
`--quiet` flag is used, just print the subrepo names, one per line.
|
||||
|
||||
The `--verbose` option will show all the recent local and upstream commits.
|
||||
|
||||
Use `--ALL` to show the subrepos of the subrepos (ie the "subsubrepos"), if
|
||||
any.
|
||||
|
||||
The `status` command accepts the `--all`, `--ALL`, `--fetch`, `--quiet` and
|
||||
`--verbose` options.
|
||||
|
||||
- `git subrepo clean <subdir>|--all|--ALL [-f]`
|
||||
|
||||
Remove artifacts created by `fetch` and `branch` commands.
|
||||
|
||||
The `fetch` and `branch` operations (and other commands that call them)
|
||||
create temporary things like refs, branches and remotes. This command
|
||||
removes all those things.
|
||||
|
||||
Use `--force` to remove refs. Refs are not removed by default because they
|
||||
are sometimes needed between commands.
|
||||
|
||||
Use `--all` to clean up after all the current subrepos. Sometimes you might
|
||||
change to a branch where a subrepo doesn't exist, and then `--all` won't find
|
||||
it. Use `--ALL` to remove any artifacts that were ever created by subrepo.
|
||||
|
||||
To remove ALL subrepo artifacts:
|
||||
|
||||
git subrepo clean --ALL --force
|
||||
|
||||
The `clean` command accepts the `--all`, `--ALL`, and `--force` options.
|
||||
|
||||
- `git subrepo config <subdir> <option> [<value>] [-f]`
|
||||
|
||||
Read or update configuration values in the subdir/.gitrepo file.
|
||||
|
||||
Because most of the values stored in the .gitrepo file are generated you
|
||||
will need to use `--force` if you want to change anything else then the
|
||||
`method` option.
|
||||
|
||||
Example to update the `method` option for a subrepo:
|
||||
|
||||
git subrepo config foo method rebase
|
||||
|
||||
- `git subrepo help [<command>|--all]`
|
||||
|
||||
Same as `git help subrepo`. Will launch the manpage. For the shorter usage,
|
||||
use `git subrepo -h`.
|
||||
|
||||
Use `git subrepo help <command>` to get help for a specific command. Use
|
||||
`--all` to get a summary of all commands.
|
||||
|
||||
The `help` command accepts the `--all` option.
|
||||
|
||||
- `git subrepo version [-q|-v]`
|
||||
|
||||
This command will display version information about git-subrepo and its
|
||||
environment. For just the version number, use `git subrepo --version`. Use
|
||||
`--verbose` for more version info, and `--quiet` for less.
|
||||
|
||||
The `version` command accepts the `--quiet` and `--verbose` options.
|
||||
|
||||
- `git subrepo upgrade`
|
||||
|
||||
Upgrade the `git-subrepo` software itself. This simply does a `git pull` on
|
||||
the git repository that the code is running from. It only works if you are on
|
||||
the `master` branch. It won't work if you installed `git-subrepo` using `make
|
||||
install`; in that case you'll need to `make install` from the latest code.
|
||||
|
||||
= Command Options
|
||||
|
||||
- `-h`
|
||||
|
||||
Show a brief view of the commands and options.
|
||||
|
||||
- `--help`
|
||||
|
||||
Gives an overview of the help options available for the subrepo command.
|
||||
|
||||
- `--version`
|
||||
|
||||
Print the git-subrepo version. Just the version number. Try the `version`
|
||||
command for more version info.
|
||||
|
||||
- `--all` (`-a`)
|
||||
|
||||
If you have multiple subrepos, issue the command to all of them (if
|
||||
applicable).
|
||||
|
||||
- `--ALL` (`-A`)
|
||||
|
||||
If you have subrepos that also have subrepos themselves, issue the command to
|
||||
ALL of them. Note that the `--ALL` option only works for a subset of the
|
||||
commands that `--all` works for.
|
||||
|
||||
- `--branch=<branch-name>` (`-b <branch-name>`)
|
||||
|
||||
Use a different upstream branch-name than the remote HEAD or the one saved in
|
||||
`.gitrepo` locally.
|
||||
|
||||
- `--dry-run` (`-N`)
|
||||
|
||||
For the push command, do everything up until the push and then print out the
|
||||
actual `git push` command needed to finish the operation.
|
||||
|
||||
- `--edit` (`-e`)
|
||||
|
||||
Edit the commit message before committing.
|
||||
|
||||
- `--fetch` (`-F`)
|
||||
|
||||
Use this option to fetch the upstream commits, before running the command.
|
||||
|
||||
- `--force` (`-f`)
|
||||
|
||||
Use this option to force certain commands that fail in the general case.
|
||||
|
||||
NOTE: The `--force` option means different things for different commands.
|
||||
Read the command specific doc for the exact meaning.
|
||||
|
||||
- `--merge` (`-M`)
|
||||
|
||||
Use a `merge` strategy to include upstream subrepo commits on a pull (or
|
||||
setup for push).
|
||||
|
||||
- `--message=<message>` (`-m <message>`)
|
||||
|
||||
Specify your own commit message on the command line.
|
||||
|
||||
- `--rebase` (`-R`)
|
||||
|
||||
Use a `rebase` strategy to include upstream subrepo commits on a pull (or
|
||||
setup for push).
|
||||
|
||||
- `--remote=<remote-url>` (`-r <remote-url>`)
|
||||
|
||||
Use a different remote-url than the one saved in `.gitrepo` locally.
|
||||
|
||||
- `--squash` (`-s`)
|
||||
|
||||
Squash all commits on a push into one new commit.
|
||||
|
||||
- `--update` (`-u`)
|
||||
|
||||
If `--branch` or `--remote` are used, and the command updates the `.gitrepo`
|
||||
file, include these values to the update.
|
||||
|
||||
= Output Options
|
||||
|
||||
- `--quiet` (`-q`)
|
||||
|
||||
Print as little info as possible. Applicable to most commands.
|
||||
|
||||
- `--verbose` (`-v`)
|
||||
|
||||
Print more information about the command execution and results. Applicable
|
||||
to most commands.
|
||||
|
||||
- `--debug` (`-d`)
|
||||
|
||||
Show the actual git (and other) commands being executed under the hood.
|
||||
Applicable to most commands.
|
||||
|
||||
- `--DEBUG` (`-x`)
|
||||
|
||||
Use the Bash `set -x` option which prints every command before it is run.
|
||||
VERY noisy, but extremely useful in deep debugging. Applicable to all
|
||||
commands.
|
||||
|
||||
= Environment Variables
|
||||
|
||||
The `git-subrepo` command exports and honors some environment variables:
|
||||
|
||||
- `GIT_SUBREPO_ROOT`
|
||||
|
||||
This is set by the `.rc` file, if you use that method to install / enable
|
||||
`git-subrepo`. It contains the path of the `git-subrepo` repository.
|
||||
|
||||
- `GIT_SUBREPO_RUNNING`
|
||||
|
||||
This variable is exported when `git-subrepo` is running. It is set to the pid
|
||||
of the `git-subrepo` process that is running. Other processes, like git hooks
|
||||
for instance, can use this information to adjust accordingly.
|
||||
|
||||
- `GIT_SUBREPO_COMMAND`
|
||||
|
||||
This variable is exported when `git-subrepo` is running. It is set to the
|
||||
name of the `git-subrepo` subcommand that is running.
|
||||
|
||||
- `GIT_SUBREPO_PAGER`
|
||||
|
||||
Use this to specify the pager to use for long output commands. Defaults to
|
||||
`$PAGER` or `less`.
|
||||
|
||||
- `GIT_SUBREPO_QUIET`
|
||||
|
||||
Set this for quiet (`-q`) output.
|
||||
|
||||
- `GIT_SUBREPO_VERBOSE`
|
||||
|
||||
Set this for verbose (`-v`) output.
|
||||
|
||||
- `GIT_SUBREPO_DEBUG`
|
||||
|
||||
Set this for debugging (`-d`) output.
|
||||
|
||||
= Installation Instructions
|
||||
|
||||
There are currently 3 ways to install `git-subrepo`. For all of them you need
|
||||
to get the source code from GitHub:
|
||||
|
||||
git clone https://github.com/ingydotnet/git-subrepo /path/to/git-subrepo
|
||||
|
||||
The first installation method is preferred: `source` the `.rc` file. Just add a
|
||||
line like this one to your shell startup script:
|
||||
|
||||
source /path/to/git-subrepo/.rc
|
||||
|
||||
That will modify your `PATH` and `MANPATH`, and also enable command completion.
|
||||
|
||||
The second method is to do these things by hand. This might afford you more
|
||||
control of your shell environment. Simply add the `lib` and `man` directories
|
||||
to your `PATH` and `MANPATH`:
|
||||
|
||||
export GIT_SUBREPO_ROOT="/path/to/git-subrepo"
|
||||
export PATH="/path/to/git-subrepo/lib:$PATH"
|
||||
export MANPATH="/path/to/git-subrepo/man:$MANPATH"
|
||||
|
||||
See below for info on how to turn on Command Completion.
|
||||
|
||||
The third method is a standard system install, which puts `git-subrepo` next to
|
||||
your other git commands:
|
||||
|
||||
make install # Possibly with 'sudo'
|
||||
|
||||
This method does not account for upgrading and command completion yet.
|
||||
|
||||
== Windows
|
||||
|
||||
This command is known to work in these Windows environments:
|
||||
|
||||
* Git for Windows -- https://git-for-windows.github.io/
|
||||
* Babun -- http://babun.github.io/
|
||||
* Cygwin -- https://www.cygwin.com/
|
||||
|
||||
Let us know if there are others that it works (or doesn't work) in.
|
||||
|
||||
= Testing
|
||||
|
||||
The `git-subrepo` repository comes with a extensive test suite. You can run it
|
||||
with:
|
||||
|
||||
make test
|
||||
|
||||
or if you don't have `make` on your system:
|
||||
|
||||
prove -v test
|
||||
|
||||
= Upgrading
|
||||
|
||||
If you used the `.rc` or `PATH` method of installation, just run this to
|
||||
upgrade `git-subrepo`:
|
||||
|
||||
git subrepo upgrade
|
||||
|
||||
Or (same thing):
|
||||
|
||||
cd /path/to/git-subrepo
|
||||
git pull
|
||||
|
||||
If you used `make install` method, then run this again (after `git pull`):
|
||||
|
||||
make install # Possibly with 'sudo'
|
||||
|
||||
= Command Completion
|
||||
|
||||
The `git subrepo` command supports `<TAB>`-based command completion. If you
|
||||
don't use the `.rc` script (see Installation, above), you'll need to enable
|
||||
this manually to use it.
|
||||
|
||||
== In Bash
|
||||
|
||||
If your Bash setup does not already provide command completion for Git, you'll
|
||||
need to enable that first:
|
||||
|
||||
source <Git completion script>
|
||||
|
||||
On your system, the Git completion script might be found at any of the
|
||||
following locations (or somewhere else that we don't know about):
|
||||
|
||||
* `/etc/bash_completion.d/git`
|
||||
* `/usr/share/bash-completion/git`
|
||||
* `/usr/share/bash-completion/completions/git`
|
||||
* `/opt/local/share/bash-completion/completions/git`
|
||||
* `/usr/local/etc/bash_completion.d/git`
|
||||
* `~/.homebrew/etc/bash_completion.d/git`
|
||||
|
||||
In case you can't find any of these, this repository contains a copy of the
|
||||
Git completion script:
|
||||
|
||||
source /path/to/git-subrepo/share/git-completion.bash
|
||||
|
||||
Once Git completion is enabled (whether you needed to do that manually or
|
||||
not), you can turn on `git-subrepo` completion with a command like this:
|
||||
|
||||
source /path/to/git-subrepo/share/completion.bash
|
||||
|
||||
== In zsh
|
||||
|
||||
In the Z shell (zsh), you can manually enable `git-subrepo` completion by
|
||||
adding the following line to your `~/.zshrc`, *before* the `compinit` function
|
||||
is called:
|
||||
|
||||
fpath=('/path/to/git-subrepo/share/zsh-completion' $fpath)
|
||||
|
||||
= Status
|
||||
|
||||
The git-subrepo command has been in use for well over a year and seems to get
|
||||
the job done. Development is still ongoing but mostly just for fixing bugs.
|
||||
|
||||
Trying subrepo out is simple and painless (this is not `git submodule`).
|
||||
Nothing is permanent (if you do not push to shared remotes). ie You can always
|
||||
play around and reset back to the beginning without pain.
|
||||
|
||||
This command has a test suite (run `make test`), but surely has many bugs. If
|
||||
you have expertise with Git and subcommands, please review the code, and file
|
||||
issues on anything that seems wrong.
|
||||
|
||||
If you want to chat about the `git-subrepo` command, join `#gitcommands` on
|
||||
`irc.freenode.net`.
|
||||
|
||||
= Notes
|
||||
|
||||
* Works on POSIX systems: Linux, BSD, OSX, etc.
|
||||
* Works on various Windows environments. See "Windows" section above.
|
||||
* The `git-subrepo` repo itself has 2 subrepos under the `ext/` subdirectory.
|
||||
* Written in (very modern) Bash, with full test suite. Take a look.
|
||||
* A `.gitrepo` file never is in the top level dir (next to a `.git/` dir).
|
||||
|
||||
= Authors
|
||||
|
||||
* Ingy döt Net <ingy@ingy.net>
|
||||
* Magnus Carlsson <grimmymail@gmail.com>
|
||||
|
||||
= License and Copyright
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2020 Ingy döt Net
|
||||
387
build/git-subrepo/doc/intro-to-subrepo.swim
Normal file
387
build/git-subrepo/doc/intro-to-subrepo.swim
Normal file
|
|
@ -0,0 +1,387 @@
|
|||
= Introducing Git Subrepos
|
||||
|
||||
There is a new git command called `subrepo` that is meant to be a solid
|
||||
alternative to the `submodule` and `subtree` commands. All 3 of these commands
|
||||
allow you to include external repositories (pinned to specific commits) in
|
||||
your main repository. This is an often needed feature for project development
|
||||
under a source control system like Git. Unfortunately, the `submodule` command
|
||||
is severely lacking, and the `subtree` command (an attempt to make things
|
||||
better) is also very flawed. Fortunately, the `subrepo` command is here to
|
||||
save the day.
|
||||
|
||||
This article will discuss how the previous commands work, and where they go
|
||||
wrong, while explaining how the new `subrepo` command fixes the issues.
|
||||
|
||||
It should be noted that there are 3 distinct roles (ways people use repos)
|
||||
involved in discussing this topic:
|
||||
|
||||
* *owner* — The primary author and repo owner
|
||||
* *collaborators* — Other developers who contribute to the repo
|
||||
* *users* — People who simply use the repo software
|
||||
|
||||
== Introducing `subrepo`
|
||||
|
||||
While the main point is to show how subrepo addresses the shortcomings of
|
||||
submodule and subtree, I'll start by giving a quick intro to the subrepo
|
||||
command.
|
||||
|
||||
Let's say that you have a project repo called 'freebird' and you want to have
|
||||
it include 2 other external repos, 'lynyrd' and 'skynyrd'. You would do the
|
||||
following:
|
||||
|
||||
git clone git@github.com/you/freebird
|
||||
cd freebird
|
||||
git subrepo clone git@github.com/you/lynyrd ext/lynyrd
|
||||
git subrepo clone git@github.com/you/skynyrd ext/skynyrd --branch=1975
|
||||
|
||||
What these commands do (at a high level) should be obvious. They "clone"
|
||||
(add) the repos content into the subdirectories you told them to. The details
|
||||
of what is happening to your repo will be discussed later, but adding new
|
||||
subrepos is easy. If you need to update the subrepos later:
|
||||
|
||||
git subrepo pull ext/lynyrd
|
||||
git subrepo pull ext/skynyrd --branch=1976
|
||||
|
||||
The lynyrd repo is tracking the upstream master branch, and you've changed the
|
||||
skynyrd subrepo to the 1976 branch. Since these subrepos are owned by 'you',
|
||||
you might want to change them in the context of your freebird repo. When
|
||||
things are working, you can push the subrepo changes back:
|
||||
|
||||
git subrepo push ext/lynyrd
|
||||
git subrepo push ext/skynyrd
|
||||
|
||||
Looks simple right? It's supposed to be. The intent of `subrepo` is to do the
|
||||
right things, and to not cause problems.
|
||||
|
||||
Of course there's more to it under the hood, and that's what the rest of this
|
||||
article is about.
|
||||
|
||||
== Git Submodules
|
||||
|
||||
Submodules tend to receive a lot of bad press. Here's some of it:
|
||||
|
||||
* http://ayende.com/blog/4746/the-problem-with-git-submodules
|
||||
* http://somethingsinistral.net/blog/git-submodules-are-probably-not-the-answer/
|
||||
* http://codingkilledthecat.wordpress.com/2012/04/28/why-your-company-shouldnt-use-git-submodules/
|
||||
|
||||
A quick recap of some of the good and bad things about submodules:
|
||||
|
||||
Good:
|
||||
|
||||
* Use an external repo in a dedicated subdir of your project.
|
||||
* Pin the external repo to a specific commit.
|
||||
* The `git-submodule` command is a core part of the Git project.
|
||||
|
||||
Bad:
|
||||
|
||||
* Users have to know a repo has submodules.
|
||||
* Users have to get the subrepos manually.
|
||||
* Pulling a repo with submodules won't pull in the new submodule changes.
|
||||
* A submodule will break if the referenced repo goes away.
|
||||
* A submodule will break if a forced push removes the referenced commit.
|
||||
* Can't use different submodules/commits per main project branch.
|
||||
* Can't "try out" a submodule on alternate branch.
|
||||
* Main repo can be pushed upstream pointing to unpushed submod commits.
|
||||
* Command capability differs across Git versions.
|
||||
* Often need to change remote url, to push submodule changes upstream.
|
||||
* Removing or renaming a submodule requires many steps.
|
||||
|
||||
Internally, submodules are a real mess. They give the strong impression of
|
||||
being bolted on, well after Git was designed. Some commands are aware of the
|
||||
existence of submodules (although usually half-heartedly), and many commands
|
||||
are oblivious. For instance the git-clone command has a `--recursive` option
|
||||
to clone all subrepos, but it's not a default, so you still need to be aware
|
||||
of the need. The git-checkout command does nothing with the submodules, even
|
||||
if they are intended to differ across branches.
|
||||
|
||||
Let's talk a bit about how submodules are implemented in Git. Information
|
||||
about them is stored in 3 different places (in the top level repo directory):
|
||||
|
||||
* `.gitmodules`
|
||||
* `.git/config`
|
||||
* `.git/modules` — The submodule repo's meta data (refs/objects)
|
||||
|
||||
So some of the information lives in the repo history (.gitmodules), but other
|
||||
info (.git/) is only known to the local repo.
|
||||
|
||||
In addition, the submodule introduces a new low level concept, to the
|
||||
commit/tree/blob graph. Normally a git tree object points to blob (file)
|
||||
objects and more tree (directory) objects. Submodules have tree objects point
|
||||
to *commit* objects. While this seems clever and somewhat reasonable, it also
|
||||
means that every other git command (which was built on the super clean Git
|
||||
data model) has to be aware of this new possibility (and deal with it
|
||||
appropriately).
|
||||
|
||||
The point is that, while submodules are a real need, and a lot of work has
|
||||
gone into making them work decently, they are essentially a kludge to the Git
|
||||
model, and it is quite understandable why they haven't worked out as well as
|
||||
people would expect.
|
||||
|
||||
NOTE: Submodules /are/ getting better with each release of Git, but it's still
|
||||
an endless catch up game.
|
||||
|
||||
== Git Subtrees
|
||||
|
||||
One day, someone decided to think different. Instead of pointing to external
|
||||
repos, why not just include them into the main repo (but also allow them to be
|
||||
pulled and pushed separately as needed)?
|
||||
|
||||
At first this may feel like a wasteful approach. Why keep other repos
|
||||
physically inside your main one? But if you think about it abstractly, what's
|
||||
the difference? You want your users and collaborators to have all this code
|
||||
because your project needs it. So why worry about how it happens? In the end,
|
||||
the choice is yours, but I've grown very comfortable with this concept and
|
||||
I'll try to justify it well. I should note that the first paragraph of the
|
||||
`submodule` doc suggests considering this alternative.
|
||||
|
||||
The big win here is that you can do this using the existing git model.
|
||||
Nothing new is added. You are just adding commits to a history. You can do it
|
||||
different on every branch. You can merge branches sensibly.
|
||||
|
||||
The git-subtree command seems to have been inspired by Git's subtree merge
|
||||
strategy, which it uses internally, and possibly got its name from. A subtree
|
||||
merge allows you to take a completely separate Git history and make it be a
|
||||
subdirectory of your repo.
|
||||
|
||||
Adding a subtree was the easy part. All that needed to be done after that was
|
||||
to figure out a way to pull upstream changes and push local ones back
|
||||
upstream. And that's what the `git-subtree` command does.
|
||||
|
||||
So what's the problem with git-subtree then?
|
||||
|
||||
Well unfortunately, it drops a few balls. The main problems come down to an
|
||||
overly complicated commandline UX, poor collaborator awareness, and a fragile
|
||||
and messy implementation.
|
||||
|
||||
Good:
|
||||
|
||||
* Use an external repo in a dedicated subdir of your project.
|
||||
* Pin the external repo to a specific commit.
|
||||
* Users get everything with a normal clone command.
|
||||
* Users don't need to know that subtrees are involved.
|
||||
* Can use different submodules/commits per main project branch.
|
||||
* Users don't need the subtree command. Only owners and collaborators.
|
||||
|
||||
Bad:
|
||||
* The remote url and branch info is not saved (except in the history).
|
||||
* Owners and collaborators have to enter the remote for every command.
|
||||
* Collaborators aren't made aware that subtrees are involved.
|
||||
* Pulled history is not squashed by default.
|
||||
* Creates a messy historical view. (See below)
|
||||
* Bash code is complicated.
|
||||
* Only one test file. Currently is failing.
|
||||
|
||||
As you can see, subtree makes quite a few things better, but after trying it
|
||||
for a while, the experience was more annoying than submodules. For example,
|
||||
consider this usage:
|
||||
|
||||
$ git subtree add --squash --prefix=foo git@github.com:my/thing mybranch
|
||||
# weeks go by…
|
||||
$ git subtree pull --squash --prefix=foo git@github.com:my/thing mybranch
|
||||
# time to push local subtree changes back upstream
|
||||
$ git subtree push --prefix=foo git@github.com:my/thing mybranch
|
||||
|
||||
The first thing you notice is the overly verbose syntax. It's justified in the
|
||||
first command, but in the other 2 commands I really don't want to have to
|
||||
remember what the remote and branch are that I'm using.
|
||||
|
||||
Moreover, my collaborators have no idea that subtrees are involved, let alone
|
||||
where they came from.
|
||||
|
||||
Consider the equivalent subrepo commands:
|
||||
|
||||
$ git subrepo clone git@github.com:my/thing foo -b mybranch
|
||||
$ git subrepo pull foo
|
||||
$ git subrepo push foo
|
||||
|
||||
Collaborators see a file called 'foo/.gitrepo', and know that the subdir is a
|
||||
subrepo. The file contains all the information needed by future commands
|
||||
applied to that subrepo.
|
||||
|
||||
== Git Subrepos
|
||||
|
||||
Now is a good time to dive into the techinical aspects of the `subrepo`
|
||||
command, but first let me explain how it came about.
|
||||
|
||||
As you may have surmised by now, I am the author of git-subrepo. I'd used
|
||||
submodules on and off for years, and when I became aware of subtree I gave it
|
||||
a try, but I quickly realized its problems. I decided maybe it could be
|
||||
improved. I decided to write down my expected commandline usage and my ideals
|
||||
of what it would and would not do. Then I set off to implement it. It's been a
|
||||
long road, but what I ended up with was even better than what I wanted from
|
||||
the start.
|
||||
|
||||
Let's review the Goods and Bads:
|
||||
|
||||
Good:
|
||||
|
||||
* Use an external repo in a dedicated subdir of your project.
|
||||
* Pin the external repo to a specific commit.
|
||||
* Users get everything with a normal clone command.
|
||||
* Users don't need to know that subrepos are involved.
|
||||
* Can use different submodules/commits per main project branch.
|
||||
* Meta info is kept in an obvious place.
|
||||
* Everyone knows when a subdir is a subrepo.
|
||||
* Commandline UX is minimal and intuitive.
|
||||
* Pulled history is always squashed out locally.
|
||||
* Pushed history is kept intact.
|
||||
* Creates a clean historical view. (See below)
|
||||
* Bash code is very simple and easy to follow.
|
||||
* Comprehensive test suite. Currently passing on travis:
|
||||
|
||||
<badge travis ingydotnet/git-subrepo>
|
||||
|
||||
Bad:
|
||||
|
||||
* --Subrepo is very new.-- (no longer true)
|
||||
* --Not well tested in the wild.-- (no longer true)
|
||||
|
||||
This review may seem somewhat slanted, but I honestly am not aware of any
|
||||
"bad" points that I'm not disclosing. That said, I am sure time will reveal
|
||||
bugs and shortcomings. Those can usually be fixed. Hopefully the *model* is
|
||||
correct, because that's harder to fix down the road.
|
||||
|
||||
OK. So how does it all work?
|
||||
|
||||
There are 3 main commands: clone/pull/push. Let's start with the clone
|
||||
command. This is the easiest part. You give it a remote url, possibly a new
|
||||
subdir to put it, and possibly a remote branch to use. I say possibly, because
|
||||
the command can guess the subdir name (just like the git-clone command does),
|
||||
and the branch can be the upstream default branch.
|
||||
|
||||
Given this we do the following steps internally:
|
||||
|
||||
* Fetch the remote content (for a specific refspec)
|
||||
* Read the remote head tree into the index
|
||||
* Checkout the index into the new subdir
|
||||
* Create a new subrepo commit object for the subdir content
|
||||
* Add a state file called .gitrepo to the new subrepo/subdir
|
||||
* Amend the merge commit with this new file
|
||||
|
||||
This process adds something like this to the top of your history:
|
||||
|
||||
* 9b6ddc9 git subrepo clone git@github.com:you/foo.git foo/
|
||||
* 37c61a5 Previous head commit of your repo
|
||||
|
||||
The entire history has been squashed down into one commit, and placed on top of
|
||||
your history. This is important as it keeps your history as clean as possible.
|
||||
You don't need to have the subrepo history in your main project, since it is
|
||||
immutably available elsewhere, and you have a pointer to that place.
|
||||
|
||||
The new foo/.gitrepo file looks like this:
|
||||
|
||||
[subrepo]
|
||||
remote = git@github.com:you/foo.git
|
||||
branch = master
|
||||
commit = 14c96c6931b41257b2d42b2edc67ddc659325823
|
||||
parent = 37c61a5a234f5dd6f5c2aec037509f50d3a79b8f
|
||||
cmdver = 0.1.0
|
||||
|
||||
It contains all the info needed now and later. Note that the repo url is the
|
||||
generally pushable form, rather than the publically readable (https://…) form.
|
||||
This is the best practice. Users of your repo don't need access to this url,
|
||||
because the content is already in your repo. Only you and your collaborators
|
||||
need this url to pull/push in the future.
|
||||
|
||||
The next command is the pull command. Normally you just give it the subrepo's
|
||||
subdir path (although you can change the branch with -b), and it will get the
|
||||
other info from the subdir/.gitrepo file.
|
||||
|
||||
The pull command does these steps:
|
||||
|
||||
* Fetch the upstream content
|
||||
* Check if anything needs pulling
|
||||
* Create a branch of local subrepo commits since last pull
|
||||
* Rebase this branch onto the upstream commits
|
||||
* Commit the HEAD of the rebased content
|
||||
* Update/amend the .gitrepo file
|
||||
|
||||
=== Clean History
|
||||
|
||||
I've talked a bit about clean history but let me show you a comparison between
|
||||
subrepo and subtree. Let's run this command sequence using both methods. Note
|
||||
the differences between /both/ the command syntax required, and the branch
|
||||
history produced.
|
||||
|
||||
Subrepo first:
|
||||
|
||||
$ git subrepo clone git@github.com:user/abc
|
||||
$ git subrepo clone git@github.com:user/def xyz
|
||||
$ git subrepo pull abc
|
||||
$ git subrepo pull xyz
|
||||
|
||||
The resulting history is:
|
||||
|
||||
* b1f60cc subrepo pull xyz
|
||||
* 4fb0276 subrepo pull abc
|
||||
* bcef2a0 subrepo clone git@github.com:user/def xyz
|
||||
* bebf0db subrepo clone git@github.com:user/abc
|
||||
* 64eeaa6 (origin/master, origin/HEAD) O HAI FREND
|
||||
|
||||
Compare that to *subtree*. This:
|
||||
|
||||
$ git subtree add abc git@github.com:user/abc master
|
||||
$ git subtree add xyz git@github.com:user/def master
|
||||
$ git subtree pull abc git@github.com:user/abc master
|
||||
$ git subtree pull xyz git@github.com:user/def master
|
||||
|
||||
Produces this:
|
||||
|
||||
* 739e45a (HEAD, master) Merge commit '5f563469d886d53e19cb908b3a64e4229f88a2d1'
|
||||
|\
|
||||
| * 5f56346 Squashed 'xyz/' changes from 08c7421..365409f
|
||||
* | 641f5e5 Merge commit '8d88e90ce5f653ed2e7608a71b8693a2174ea62a'
|
||||
|\ \
|
||||
| * | 8d88e90 Squashed 'abc/' changes from 08c7421..365409f
|
||||
* | | 1703ed2 Merge commit '0e091b672c4bbbbf6bc4f6694c475d127ffa21eb' as 'xyz'
|
||||
|\ \ \
|
||||
| | |/
|
||||
| |/|
|
||||
| * | 0e091b6 Squashed 'xyz/' content from commit 08c7421
|
||||
| /
|
||||
* | 07b77e7 Merge commit 'cd2b30a0229d931979ed4436b995875ec563faea' as 'abc'
|
||||
|\ \
|
||||
| |/
|
||||
| * cd2b30a Squashed 'abc/' content from commit 08c7421
|
||||
* 64eeaa6 (origin/master, origin/HEAD) O HAI FREND
|
||||
|
||||
This was from a minimal case. Subtree history (when viewed this way at least)
|
||||
gets unreasonably ugly fast. Subrepo history, by contrast, always looks as
|
||||
clean as shown.
|
||||
|
||||
The final command, push, bascially just does the pull/rebase dance above
|
||||
described, and pushes the resulting history back. It does not squash the
|
||||
commits made locally, because it assumed that when you changed the local
|
||||
subrepo, you made messages that were intended to eventually be published back
|
||||
upstream.
|
||||
|
||||
== Conflict Resolution
|
||||
|
||||
The commands described above can also be done "by hand". If something fails
|
||||
during a pull or push (generally in the rebasing) then the command will tell
|
||||
you what to do to finish up.
|
||||
|
||||
You might choose to do everything by hand, and do your own merging strategies.
|
||||
This is perfectly reasonable. The `subrepo` command offers a few other helper
|
||||
commands to help you get the job done:
|
||||
|
||||
* `fetch` - Fetch the upstream and create a `subrepo/remote/<subdir>` ref.
|
||||
* `branch` - Create a branch of local subdir commits since the last pull,
|
||||
called `subrepo/<subdir>`.
|
||||
* `commit` - Commit a merged branch's HEAD back into your repo.
|
||||
* `status` - Show lots of useful info about the current state of the subrepos.
|
||||
* `clean` - Remove branches, ref and remotes created by subrepo commands.
|
||||
* `help` - Read the complete documentation!
|
||||
|
||||
== Conclusion
|
||||
|
||||
Hopefully by now, you see that submodules are a painful choice with a dubious
|
||||
future, and that subtree, while a solid idea has many usage issues.
|
||||
|
||||
Give `subrepo` a try. It's painless, easily revertable and just might be what
|
||||
the doctor ordered.
|
||||
|
||||
== Reference Links
|
||||
|
||||
* http://longair.net/blog/2010/06/02/git-submodules-explained/
|
||||
* http://blogs.atlassian.com/2013/05/alternatives-to-git-submodule-git-subtree/
|
||||
0
build/git-subrepo/ext/bashplus/.gitignore
vendored
Normal file
0
build/git-subrepo/ext/bashplus/.gitignore
vendored
Normal file
11
build/git-subrepo/ext/bashplus/.gitrepo
Normal file
11
build/git-subrepo/ext/bashplus/.gitrepo
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
; DO NOT EDIT (unless you know what you are doing)
|
||||
;
|
||||
; This subdirectory is a git "subrepo", and this file is maintained by the
|
||||
; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
|
||||
;
|
||||
[subrepo]
|
||||
remote = git@github.com:ingydotnet/bashplus.git
|
||||
branch = master
|
||||
commit = d9183af6f46946fabdef1dd8f37824c042a378f8
|
||||
parent = 9b8f13e94677b2680a33ad204bebadcdb1ff9081
|
||||
cmdver = 0.3.0
|
||||
6
build/git-subrepo/ext/bashplus/.travis.yml
Normal file
6
build/git-subrepo/ext/bashplus/.travis.yml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# C language gives closest shell env.
|
||||
language: c
|
||||
|
||||
script:
|
||||
- git submodule update --init --recursive
|
||||
- PROVEOPT=-v make test
|
||||
15
build/git-subrepo/ext/bashplus/Changes
Normal file
15
build/git-subrepo/ext/bashplus/Changes
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
version: 0.0.7
|
||||
date: Sat Jan 23 16:28:59 PST 2016
|
||||
changes:
|
||||
- Update tooling, and copyright
|
||||
---
|
||||
version: 0.0.6
|
||||
date: Fri Jan 23 21:05:15 PST 2015
|
||||
changes:
|
||||
- Update tooling, and copyright
|
||||
---
|
||||
version: 0.0.1
|
||||
date: Sun Oct 27 19:07:51 PDT 2013
|
||||
changes:
|
||||
- First release.
|
||||
21
build/git-subrepo/ext/bashplus/License
Normal file
21
build/git-subrepo/ext/bashplus/License
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
(The MIT License)
|
||||
|
||||
Copyright © 2013-2016 Ingy döt Net
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the ‘Software’), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
45
build/git-subrepo/ext/bashplus/Makefile
Normal file
45
build/git-subrepo/ext/bashplus/Makefile
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
ifeq ($(MAKECMDGOALS),install)
|
||||
ifeq "$(shell bpan version 2>/dev/null)" ""
|
||||
$(error 'BPAN not installed. See http://bpan.org')
|
||||
endif
|
||||
endif
|
||||
|
||||
NAME := bash+
|
||||
LIB := lib/$(NAME).bash
|
||||
DOC := doc/$(NAME).swim
|
||||
MAN1 := man/man1
|
||||
MAN3 := man/man3
|
||||
|
||||
INSTALL_LIB ?= $(shell bpan env BPAN_LIB)
|
||||
INSTALL_DIR ?= test
|
||||
INSTALL_MAN1 ?= $(shell bpan env BPAN_MAN1)
|
||||
INSTALL_MAN3 ?= $(shell bpan env BPAN_MAN3)
|
||||
|
||||
default: help
|
||||
|
||||
help:
|
||||
@echo 'Rules: test, install, doc'
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
prove $(PROVEOPT:%=% )test/
|
||||
|
||||
install:
|
||||
install -C -d -m 0755 $(INSTALL_LIB)/$(INSTALL_DIR)/
|
||||
install -C -m 0755 $(LIB) $(INSTALL_LIB)/$(INSTALL_DIR)/
|
||||
install -C -d -m 0755 $(INSTALL_MAN1)/
|
||||
install -C -d -m 0755 $(INSTALL_MAN3)/
|
||||
install -C -m 0644 $(MAN1)/$(NAME).1 $(INSTALL_MAN1)/
|
||||
install -C -m 0644 $(MAN3)/$(NAME).3 $(INSTALL_MAN3)/
|
||||
|
||||
.PHONY: doc
|
||||
doc: ReadMe.pod $(MAN1)/$(NAME).1 $(MAN3)/$(NAME).3
|
||||
|
||||
ReadMe.pod: $(DOC)
|
||||
swim --to=pod --complete --wrap $< > $@
|
||||
|
||||
$(MAN1)/%.1: doc/%.swim
|
||||
swim --to=man $< > $@
|
||||
|
||||
$(MAN3)/%.3: doc/%.swim
|
||||
swim --to=man $< > $@
|
||||
28
build/git-subrepo/ext/bashplus/Meta
Normal file
28
build/git-subrepo/ext/bashplus/Meta
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
=meta: 0.0.2
|
||||
|
||||
name: bashplus
|
||||
version: 0.0.7
|
||||
abstract: Modern Bash Programming
|
||||
homepage: http://bpan.org/package/bashplus/
|
||||
|
||||
license: MIT
|
||||
copyright: 2013-2016
|
||||
author:
|
||||
name: Ingy döt Net
|
||||
email: ingy@ingy.net
|
||||
github: ingydotnet
|
||||
twitter: ingydotnet
|
||||
freenode: ingy
|
||||
homepage: http://ingy.net
|
||||
|
||||
requires:
|
||||
bash: 3.2.0
|
||||
test:
|
||||
cmd: make test
|
||||
install:
|
||||
cmd: make install
|
||||
|
||||
devel:
|
||||
git: git@github.org/ingydotnet/bashplus
|
||||
irc: irc.freenode.net/bpan
|
||||
bug: https://github.com/ingydotnet/bashplus/issues/
|
||||
77
build/git-subrepo/ext/bashplus/ReadMe.pod
Normal file
77
build/git-subrepo/ext/bashplus/ReadMe.pod
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
=pod
|
||||
|
||||
=for comment
|
||||
DO NOT EDIT. This Pod was generated by Swim v0.1.41.
|
||||
See http://github.com/ingydotnet/swim-pm#readme
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 Name
|
||||
|
||||
Bash+(1) - Modern Bash Programming
|
||||
|
||||
=for html
|
||||
<a href="https://travis-ci.org/ingydotnet/bashplus"><img src="https://travis-ci.org/ingydotnet/bashplus.png" alt="bashplus"></a>
|
||||
|
||||
=head1 Synopsis
|
||||
|
||||
source bash+ :std :array
|
||||
|
||||
use Foo::Bar this that
|
||||
|
||||
Array.new args "$@"
|
||||
|
||||
if args.empty?; then
|
||||
die "I need args!"
|
||||
fi
|
||||
|
||||
Foo::Bar.new foo args
|
||||
|
||||
this is awesome # <= this is a real command! (You just imported it)
|
||||
|
||||
=head1 Description
|
||||
|
||||
Bash+ is just Bash... B<plus> some libraries that can make Bash programming a
|
||||
lot nicer.
|
||||
|
||||
=for comment # Installation
|
||||
|
||||
Get the source code from GitHub:
|
||||
|
||||
git clone git@github.com:ingydotnet/bashplus
|
||||
|
||||
Then run:
|
||||
|
||||
make test
|
||||
make install # Possibly with 'sudo'
|
||||
|
||||
=head1 Usage
|
||||
|
||||
For now look at some libraries the use Bash+:
|
||||
|
||||
=over
|
||||
|
||||
=item * L<https://github.com/ingydotnet/git-hub>
|
||||
|
||||
=item * L<https://github.com/ingydotnet/json-bash>
|
||||
|
||||
=item * L<https://github.com/ingydotnet/test-more-bash>
|
||||
|
||||
=back
|
||||
|
||||
=head1 Status
|
||||
|
||||
If you are interested in chatting about this, C</join #bpan> on
|
||||
irc.freenode.net.
|
||||
|
||||
=head1 Author
|
||||
|
||||
Written by Ingy döt Net <ingy@ingy.net>
|
||||
|
||||
=head1 Copyright & License
|
||||
|
||||
Copyright 2013-2016. Ingy döt Net.
|
||||
|
||||
The MIT License (MIT).
|
||||
|
||||
=cut
|
||||
43
build/git-subrepo/ext/bashplus/bin/bash+
Normal file
43
build/git-subrepo/ext/bashplus/bin/bash+
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env bash
|
||||
#------------------------------------------------------------------------------
|
||||
# Bash+ - Modern Bash Programming
|
||||
#
|
||||
# Copyright (c) 2013-2016 Ingy döt Net
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
set -e
|
||||
shopt -s compat31&>/dev/null||:
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Determine how `bash+` was called, and do the right thing:
|
||||
#------------------------------------------------------------------------------
|
||||
if [ "${BASH_SOURCE[0]}" != "$0" ]; then
|
||||
# 'bash+' is being sourced:
|
||||
[[ "${BASH_SOURCE[0]}" =~ /bin/bash\\+$ ]] || {
|
||||
echo "Invalid Bash+ path '${BASH_SOURCE[0]}'" 2> /dev/null
|
||||
exit 1
|
||||
}
|
||||
source "${BASH_SOURCE[0]%/bin/*}"/lib/bash+.bash || return $?
|
||||
bash+:import "$@"
|
||||
return $?
|
||||
else
|
||||
if [ $# -eq 1 -a "$1" == --version ]; then
|
||||
echo 'bash+ version 0.0.7'
|
||||
else
|
||||
cat <<...
|
||||
|
||||
Greetings modern Bash programmer. Welcome to Bash+!
|
||||
|
||||
Bash+ is framework that makes Bash programming more like Ruby and Perl.
|
||||
|
||||
See: https://github.com/bpan-org/bashplus
|
||||
|
||||
If you got here trying to use bash+ in a program, you need to source it:
|
||||
|
||||
source bash+
|
||||
|
||||
Happy Bash Hacking!
|
||||
|
||||
...
|
||||
fi
|
||||
fi
|
||||
61
build/git-subrepo/ext/bashplus/doc/bash+.swim
Normal file
61
build/git-subrepo/ext/bashplus/doc/bash+.swim
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
Bash+(1)
|
||||
========
|
||||
|
||||
Modern Bash Programming
|
||||
|
||||
<badge travis ingydotnet/bashplus>
|
||||
|
||||
= Synopsis
|
||||
|
||||
source bash+ :std :array
|
||||
|
||||
use Foo::Bar this that
|
||||
|
||||
Array.new args "$@"
|
||||
|
||||
if args.empty?; then
|
||||
die "I need args!"
|
||||
fi
|
||||
|
||||
Foo::Bar.new foo args
|
||||
|
||||
this is awesome # <= this is a real command! (You just imported it)
|
||||
|
||||
= Description
|
||||
|
||||
Bash+ is just Bash... *plus* some libraries that can make Bash programming a
|
||||
lot nicer.
|
||||
|
||||
## Installation
|
||||
|
||||
Get the source code from GitHub:
|
||||
|
||||
git clone git@github.com:ingydotnet/bashplus
|
||||
|
||||
Then run:
|
||||
|
||||
make test
|
||||
make install # Possibly with 'sudo'
|
||||
|
||||
= Usage
|
||||
|
||||
For now look at some libraries the use Bash+:
|
||||
|
||||
* https://github.com/ingydotnet/git-hub
|
||||
* https://github.com/ingydotnet/json-bash
|
||||
* https://github.com/ingydotnet/test-more-bash
|
||||
|
||||
= Status
|
||||
|
||||
If you are interested in chatting about this, `/join #bpan` on
|
||||
irc.freenode.net.
|
||||
|
||||
= Author
|
||||
|
||||
Written by Ingy döt Net <ingy@ingy.net>
|
||||
|
||||
= Copyright & License
|
||||
|
||||
Copyright 2013-2016. Ingy döt Net.
|
||||
|
||||
The MIT License (MIT).
|
||||
134
build/git-subrepo/ext/bashplus/man/man1/bash+.1
Normal file
134
build/git-subrepo/ext/bashplus/man/man1/bash+.1
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28)
|
||||
.\"
|
||||
.\" Standard preamble:
|
||||
.\" ========================================================================
|
||||
.de Sp \" Vertical space (when we can't use .PP)
|
||||
.if t .sp .5v
|
||||
.if n .sp
|
||||
..
|
||||
.de Vb \" Begin verbatim text
|
||||
.ft CW
|
||||
.nf
|
||||
.ne \\$1
|
||||
..
|
||||
.de Ve \" End verbatim text
|
||||
.ft R
|
||||
.fi
|
||||
..
|
||||
.\" Set up some character translations and predefined strings. \*(-- will
|
||||
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
|
||||
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
|
||||
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
|
||||
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
|
||||
.\" nothing in troff, for use with C<>.
|
||||
.tr \(*W-
|
||||
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
|
||||
.ie n \{\
|
||||
. ds -- \(*W-
|
||||
. ds PI pi
|
||||
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
|
||||
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
|
||||
. ds L" ""
|
||||
. ds R" ""
|
||||
. ds C` ""
|
||||
. ds C' ""
|
||||
'br\}
|
||||
.el\{\
|
||||
. ds -- \|\(em\|
|
||||
. ds PI \(*p
|
||||
. ds L" ``
|
||||
. ds R" ''
|
||||
. ds C`
|
||||
. ds C'
|
||||
'br\}
|
||||
.\"
|
||||
.\" Escape single quotes in literal strings from groff's Unicode transform.
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\"
|
||||
.\" If the F register is turned on, we'll generate index entries on stderr for
|
||||
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
|
||||
.\" entries marked with X<> in POD. Of course, you'll have to process the
|
||||
.\" output yourself in some meaningful fashion.
|
||||
.\"
|
||||
.\" Avoid warning from groff about undefined register 'F'.
|
||||
.de IX
|
||||
..
|
||||
.nr rF 0
|
||||
.if \n(.g .if rF .nr rF 1
|
||||
.if (\n(rF:(\n(.g==0)) \{
|
||||
. if \nF \{
|
||||
. de IX
|
||||
. tm Index:\\$1\t\\n%\t"\\$2"
|
||||
..
|
||||
. if !\nF==2 \{
|
||||
. nr % 0
|
||||
. nr F 2
|
||||
. \}
|
||||
. \}
|
||||
.\}
|
||||
.rr rF
|
||||
.\" ========================================================================
|
||||
.\"
|
||||
.IX Title "Bash+(1) 1"
|
||||
.TH Bash+(1) 1 "January 2016" "Generated by Swim v0.1.41" "Modern Bash Programming"
|
||||
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
||||
.\" way too many mistakes in technical documents.
|
||||
.if n .ad l
|
||||
.nh
|
||||
.SH "Name"
|
||||
.IX Header "Name"
|
||||
Bash+(1) \- Modern Bash Programming
|
||||
.SH "Synopsis"
|
||||
.IX Header "Synopsis"
|
||||
.Vb 1
|
||||
\& source bash+ :std :array
|
||||
\&
|
||||
\& use Foo::Bar this that
|
||||
\&
|
||||
\& Array.new args "$@"
|
||||
\&
|
||||
\& if args.empty?; then
|
||||
\& die "I need args!"
|
||||
\& fi
|
||||
\&
|
||||
\& Foo::Bar.new foo args
|
||||
\&
|
||||
\& this is awesome # <= this is a real command! (You just imported it)
|
||||
.Ve
|
||||
.SH "Description"
|
||||
.IX Header "Description"
|
||||
Bash+ is just Bash... \fBplus\fR some libraries that can make Bash programming a lot nicer.
|
||||
.PP
|
||||
Get the source code from GitHub:
|
||||
.PP
|
||||
.Vb 1
|
||||
\& git clone git@github.com:ingydotnet/bashplus
|
||||
.Ve
|
||||
.PP
|
||||
Then run:
|
||||
.PP
|
||||
.Vb 2
|
||||
\& make test
|
||||
\& make install # Possibly with \*(Aqsudo\*(Aq
|
||||
.Ve
|
||||
.SH "Usage"
|
||||
.IX Header "Usage"
|
||||
For now look at some libraries the use Bash+:
|
||||
.IP "\(bu" 4
|
||||
<https://github.com/ingydotnet/git\-hub>
|
||||
.IP "\(bu" 4
|
||||
<https://github.com/ingydotnet/json\-bash>
|
||||
.IP "\(bu" 4
|
||||
<https://github.com/ingydotnet/test\-more\-bash>
|
||||
.SH "Status"
|
||||
.IX Header "Status"
|
||||
If you are interested in chatting about this, \f(CW\*(C`/join #bpan\*(C'\fR on irc.freenode.net.
|
||||
.SH "Author"
|
||||
.IX Header "Author"
|
||||
Written by Ingy döt Net <ingy@ingy.net>
|
||||
.SH "Copyright & License"
|
||||
.IX Header "Copyright & License"
|
||||
Copyright 2013\-2016. Ingy döt Net.
|
||||
.PP
|
||||
The \s-1MIT\s0 License (\s-1MIT\s0).
|
||||
134
build/git-subrepo/ext/bashplus/man/man3/bash+.3
Normal file
134
build/git-subrepo/ext/bashplus/man/man3/bash+.3
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28)
|
||||
.\"
|
||||
.\" Standard preamble:
|
||||
.\" ========================================================================
|
||||
.de Sp \" Vertical space (when we can't use .PP)
|
||||
.if t .sp .5v
|
||||
.if n .sp
|
||||
..
|
||||
.de Vb \" Begin verbatim text
|
||||
.ft CW
|
||||
.nf
|
||||
.ne \\$1
|
||||
..
|
||||
.de Ve \" End verbatim text
|
||||
.ft R
|
||||
.fi
|
||||
..
|
||||
.\" Set up some character translations and predefined strings. \*(-- will
|
||||
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
|
||||
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
|
||||
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
|
||||
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
|
||||
.\" nothing in troff, for use with C<>.
|
||||
.tr \(*W-
|
||||
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
|
||||
.ie n \{\
|
||||
. ds -- \(*W-
|
||||
. ds PI pi
|
||||
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
|
||||
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
|
||||
. ds L" ""
|
||||
. ds R" ""
|
||||
. ds C` ""
|
||||
. ds C' ""
|
||||
'br\}
|
||||
.el\{\
|
||||
. ds -- \|\(em\|
|
||||
. ds PI \(*p
|
||||
. ds L" ``
|
||||
. ds R" ''
|
||||
. ds C`
|
||||
. ds C'
|
||||
'br\}
|
||||
.\"
|
||||
.\" Escape single quotes in literal strings from groff's Unicode transform.
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\"
|
||||
.\" If the F register is turned on, we'll generate index entries on stderr for
|
||||
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
|
||||
.\" entries marked with X<> in POD. Of course, you'll have to process the
|
||||
.\" output yourself in some meaningful fashion.
|
||||
.\"
|
||||
.\" Avoid warning from groff about undefined register 'F'.
|
||||
.de IX
|
||||
..
|
||||
.nr rF 0
|
||||
.if \n(.g .if rF .nr rF 1
|
||||
.if (\n(rF:(\n(.g==0)) \{
|
||||
. if \nF \{
|
||||
. de IX
|
||||
. tm Index:\\$1\t\\n%\t"\\$2"
|
||||
..
|
||||
. if !\nF==2 \{
|
||||
. nr % 0
|
||||
. nr F 2
|
||||
. \}
|
||||
. \}
|
||||
.\}
|
||||
.rr rF
|
||||
.\" ========================================================================
|
||||
.\"
|
||||
.IX Title "Bash+(1) 1"
|
||||
.TH Bash+(1) 1 "January 2016" "Generated by Swim v0.1.41" "Modern Bash Programming"
|
||||
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
||||
.\" way too many mistakes in technical documents.
|
||||
.if n .ad l
|
||||
.nh
|
||||
.SH "Name"
|
||||
.IX Header "Name"
|
||||
Bash+(1) \- Modern Bash Programming
|
||||
.SH "Synopsis"
|
||||
.IX Header "Synopsis"
|
||||
.Vb 1
|
||||
\& source bash+ :std :array
|
||||
\&
|
||||
\& use Foo::Bar this that
|
||||
\&
|
||||
\& Array.new args "$@"
|
||||
\&
|
||||
\& if args.empty?; then
|
||||
\& die "I need args!"
|
||||
\& fi
|
||||
\&
|
||||
\& Foo::Bar.new foo args
|
||||
\&
|
||||
\& this is awesome # <= this is a real command! (You just imported it)
|
||||
.Ve
|
||||
.SH "Description"
|
||||
.IX Header "Description"
|
||||
Bash+ is just Bash... \fBplus\fR some libraries that can make Bash programming a lot nicer.
|
||||
.PP
|
||||
Get the source code from GitHub:
|
||||
.PP
|
||||
.Vb 1
|
||||
\& git clone git@github.com:ingydotnet/bashplus
|
||||
.Ve
|
||||
.PP
|
||||
Then run:
|
||||
.PP
|
||||
.Vb 2
|
||||
\& make test
|
||||
\& make install # Possibly with \*(Aqsudo\*(Aq
|
||||
.Ve
|
||||
.SH "Usage"
|
||||
.IX Header "Usage"
|
||||
For now look at some libraries the use Bash+:
|
||||
.IP "\(bu" 4
|
||||
<https://github.com/ingydotnet/git\-hub>
|
||||
.IP "\(bu" 4
|
||||
<https://github.com/ingydotnet/json\-bash>
|
||||
.IP "\(bu" 4
|
||||
<https://github.com/ingydotnet/test\-more\-bash>
|
||||
.SH "Status"
|
||||
.IX Header "Status"
|
||||
If you are interested in chatting about this, \f(CW\*(C`/join #bpan\*(C'\fR on irc.freenode.net.
|
||||
.SH "Author"
|
||||
.IX Header "Author"
|
||||
Written by Ingy döt Net <ingy@ingy.net>
|
||||
.SH "Copyright & License"
|
||||
.IX Header "Copyright & License"
|
||||
Copyright 2013\-2016. Ingy döt Net.
|
||||
.PP
|
||||
The \s-1MIT\s0 License (\s-1MIT\s0).
|
||||
12
build/git-subrepo/ext/bashplus/test/base.t
Normal file
12
build/git-subrepo/ext/bashplus/test/base.t
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
source test/test.bash
|
||||
|
||||
PATH=$PWD/bin:$PATH
|
||||
source bash+ :std
|
||||
|
||||
ok $? '`source bash+` works'
|
||||
|
||||
is "$BASHPLUS_VERSION" '0.0.7' 'BASHPLUS_VERSION is 0.0.7'
|
||||
|
||||
done_testing 2
|
||||
22
build/git-subrepo/ext/bashplus/test/fcopy.t
Normal file
22
build/git-subrepo/ext/bashplus/test/fcopy.t
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
source test/test.bash
|
||||
|
||||
PATH=$PWD/bin:$PATH
|
||||
source bash+
|
||||
|
||||
foo() {
|
||||
echo O HAI
|
||||
}
|
||||
|
||||
like "$(type bar 2>&1)" 'bar: not found' \
|
||||
'bar is not yet a function'
|
||||
|
||||
bash+:fcopy foo bar
|
||||
|
||||
type -t bar &>/dev/null
|
||||
ok $? 'bar is now a function'
|
||||
is "$(type foo | tail -n+3)" "$(type bar | tail -n+3)" \
|
||||
'Copy matches original'
|
||||
|
||||
done_testing 3
|
||||
18
build/git-subrepo/ext/bashplus/test/source-bash+-std.t
Normal file
18
build/git-subrepo/ext/bashplus/test/source-bash+-std.t
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
source test/test.bash
|
||||
|
||||
PATH=$PWD/bin:$PATH
|
||||
source bash+ :std
|
||||
|
||||
ok "`bash+:can use`" 'use is imported'
|
||||
ok "`bash+:can die`" 'die is imported'
|
||||
ok "`bash+:can warn`" 'warn is imported'
|
||||
|
||||
ok "`! bash+:can import`" 'import is not imported'
|
||||
ok "`! bash+:can main`" 'main is not imported'
|
||||
ok "`! bash+:can fcopy`" 'fcopy is not imported'
|
||||
ok "`! bash+:can findlib`" 'findlib is not imported'
|
||||
ok "`! bash+:can can`" 'can is not imported'
|
||||
|
||||
done_testing 8
|
||||
23
build/git-subrepo/ext/bashplus/test/source-bash+.t
Normal file
23
build/git-subrepo/ext/bashplus/test/source-bash+.t
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
source test/test.bash
|
||||
|
||||
PATH=$PWD/bin:$PATH
|
||||
source bash+
|
||||
|
||||
functions=(
|
||||
use
|
||||
import
|
||||
fcopy
|
||||
findlib
|
||||
die
|
||||
warn
|
||||
can
|
||||
)
|
||||
|
||||
for f in ${functions[@]}; do
|
||||
is "$(type -t "bash+:$f")" function \
|
||||
"bash+:$f is a function"
|
||||
done
|
||||
|
||||
done_testing 7
|
||||
70
build/git-subrepo/ext/bashplus/test/test.bash
Normal file
70
build/git-subrepo/ext/bashplus/test/test.bash
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# This is a tiny version of test-more-bash that I use here. test-more-bash uses
|
||||
# bash+, so I want to avoid the circular dependency. This little guy does
|
||||
# 80-90% what test-more-bash does, with minimal code. It's a good example of
|
||||
# how nice Bash can be.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
plan() {
|
||||
echo "1..$1"
|
||||
}
|
||||
|
||||
pass() {
|
||||
let run=run+1
|
||||
echo "ok $run${1:+ - $1}"
|
||||
}
|
||||
|
||||
fail() {
|
||||
let run=run+1
|
||||
echo "not ok $run${1:+ - $1}"
|
||||
}
|
||||
|
||||
is() {
|
||||
if [ "$1" == "$2" ]; then
|
||||
pass "$3"
|
||||
else
|
||||
fail "$3"
|
||||
diag "Got: $1"
|
||||
diag "Want: $2"
|
||||
fi
|
||||
}
|
||||
|
||||
ok() {
|
||||
(exit ${1:-$?}) &&
|
||||
pass "$2" ||
|
||||
fail "$2"
|
||||
}
|
||||
|
||||
like() {
|
||||
if [[ "$1" =~ "$2" ]]; then
|
||||
pass "$3"
|
||||
else
|
||||
fail "$3"
|
||||
diag "Got: $1"
|
||||
diag "Like: $2"
|
||||
fi
|
||||
}
|
||||
|
||||
unlike() {
|
||||
if [[ ! "$1" =~ "$2" ]]; then
|
||||
pass "$3"
|
||||
else
|
||||
fail "$3"
|
||||
diag "Got: $1"
|
||||
diag "Dont: $2"
|
||||
fi
|
||||
}
|
||||
|
||||
done_testing() {
|
||||
echo "1..${1:-$run}"
|
||||
}
|
||||
|
||||
diag() {
|
||||
echo "# ${1//$'\n'/$'\n'# }" >&2
|
||||
}
|
||||
|
||||
note() {
|
||||
echo "# ${1//$'\n'/$'\n'# }"
|
||||
}
|
||||
19
build/git-subrepo/ext/bashplus/test/use.t
Normal file
19
build/git-subrepo/ext/bashplus/test/use.t
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
source test/test.bash
|
||||
|
||||
PATH=$PWD/bin:$PATH
|
||||
source bash+ :std can
|
||||
|
||||
BASHLIB=test/lib
|
||||
|
||||
use Foo::Bar
|
||||
ok $? 'use Foo::Bar - works'
|
||||
ok "`can Foo::Bar:baz`" 'Function Foo::Bar:baz exists'
|
||||
is "$Foo__Bar_VERSION" 1.2.3 '$Foo__Bar_VERSION == 1.2.3'
|
||||
|
||||
output=`use Foo::Foo Boo Booo`
|
||||
ok $? 'use Foo::Foo Boo Booo - works'
|
||||
is "$output" Boo---Booo 'Correct import called'
|
||||
|
||||
done_testing 5
|
||||
11
build/git-subrepo/ext/test-more-bash/.gitrepo
Normal file
11
build/git-subrepo/ext/test-more-bash/.gitrepo
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
; DO NOT EDIT (unless you know what you are doing)
|
||||
;
|
||||
; This subdirectory is a git "subrepo", and this file is maintained by the
|
||||
; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
|
||||
;
|
||||
[subrepo]
|
||||
remote = git@github.com:ingydotnet/test-more-bash.git
|
||||
branch = master
|
||||
commit = 24a6cceabff4d62a5fd25b8945bab6f618fb0b88
|
||||
parent = 69e22c2e7f6aeadfecb8b00d57c976958da03733
|
||||
cmdver = 0.3.0
|
||||
6
build/git-subrepo/ext/test-more-bash/.travis.yml
Normal file
6
build/git-subrepo/ext/test-more-bash/.travis.yml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# C language gives closest shell env.
|
||||
language: c
|
||||
|
||||
script:
|
||||
- git submodule update --init --recursive
|
||||
- PROVEOPT=-v make test
|
||||
15
build/git-subrepo/ext/test-more-bash/Changes
Normal file
15
build/git-subrepo/ext/test-more-bash/Changes
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
version: 0.0.3
|
||||
date: Sat Jan 23 16:39:20 PST 2016
|
||||
changes:
|
||||
- Make up to date
|
||||
---
|
||||
version: 0.0.2
|
||||
date: Fri Jan 23 21:26:18 PST 2015
|
||||
changes:
|
||||
- Make up to date
|
||||
---
|
||||
version: 0.0.1
|
||||
date: Sun Oct 27 22:53:10 PDT 2013
|
||||
changes:
|
||||
- First release.
|
||||
21
build/git-subrepo/ext/test-more-bash/License
Normal file
21
build/git-subrepo/ext/test-more-bash/License
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
(The MIT License)
|
||||
|
||||
Copyright © 2013-2016. Ingy döt Net.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the ‘Software’), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
20
build/git-subrepo/ext/test-more-bash/Makefile
Normal file
20
build/git-subrepo/ext/test-more-bash/Makefile
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
NAME := test-more
|
||||
DOC := doc/$(NAME).swim
|
||||
MAN3 := man/man3
|
||||
|
||||
default: help
|
||||
|
||||
help:
|
||||
@echo 'Rules: test, doc'
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
prove $(PROVEOPT:%=% )test/
|
||||
|
||||
doc: ReadMe.pod $(MAN3)/$(NAME).3
|
||||
|
||||
ReadMe.pod: $(DOC)
|
||||
swim --to=pod --complete --wrap $< > $@
|
||||
|
||||
$(MAN3)/%.3: doc/%.swim
|
||||
swim --to=man $< > $@
|
||||
30
build/git-subrepo/ext/test-more-bash/Meta
Normal file
30
build/git-subrepo/ext/test-more-bash/Meta
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
=meta: 0.0.2
|
||||
|
||||
name: test-more
|
||||
version: 0.0.3
|
||||
abstract: TAP Testing for Bash
|
||||
homepage: http://bpan.org/package/test-more/
|
||||
|
||||
license: MIT
|
||||
copyright: 2013-2016
|
||||
author:
|
||||
name: Ingy döt Net
|
||||
email: ingy@ingy.net
|
||||
github: ingydotnet
|
||||
twitter: ingydotnet
|
||||
freenode: ingy
|
||||
homepage: http://ingy.net
|
||||
|
||||
requires:
|
||||
bash: 3.2.0
|
||||
bashplus: 0.0.7
|
||||
test-tap: 0.0.4
|
||||
test:
|
||||
cmd: make test
|
||||
install:
|
||||
cmd: make install
|
||||
|
||||
devel:
|
||||
git: git@github.org/ingydotnet/test-more-bash.git
|
||||
irc: irc.freenode.net#bpan
|
||||
bug: https://github.com/ingydotnet/test-more-bash/issues/
|
||||
115
build/git-subrepo/ext/test-more-bash/ReadMe.pod
Normal file
115
build/git-subrepo/ext/test-more-bash/ReadMe.pod
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
=pod
|
||||
|
||||
=for comment
|
||||
DO NOT EDIT. This Pod was generated by Swim v0.1.41.
|
||||
See http://github.com/ingydotnet/swim-pm#readme
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 Name
|
||||
|
||||
Test::More - TAP Testing for Bash
|
||||
|
||||
=for html
|
||||
<a href="https://travis-ci.org/ingydotnet/test-more-bash"><img src="https://travis-ci.org/ingydotnet/test-more-bash.png" alt="test-more-bash"></a>
|
||||
|
||||
=head1 Synopsis
|
||||
|
||||
Write a test file like this. Maybe call it C<test/test.t>:
|
||||
|
||||
#!/usr/bin/env bash
|
||||
|
||||
TEST_MORE_PATH="/path/to/test-more-bash"
|
||||
BASHLIB="`
|
||||
find $TEST_MORE_PATH -type d |
|
||||
grep -E '/(bin|lib)$' |
|
||||
xargs -n1 printf "%s:"`"
|
||||
PATH="$BASHLIB$PATH"
|
||||
|
||||
source bash+ :std
|
||||
|
||||
use Test::More
|
||||
|
||||
plan tests 8
|
||||
|
||||
some-command
|
||||
ok $? 'some-command is ok'
|
||||
|
||||
# or:
|
||||
ok "`some-command`" 'some-command is ok'
|
||||
|
||||
pass 'This will always pass'
|
||||
|
||||
fail 'This will always fail'
|
||||
|
||||
is `echo foo` 'foo' 'foo is foo'
|
||||
|
||||
isnt foo bar "foo isn't bar"
|
||||
|
||||
like food foo 'food is like foo'
|
||||
|
||||
unlike team I "There's no 'I' in 'team'"
|
||||
|
||||
diag "A message for stderr"
|
||||
|
||||
note "A message for stdout"
|
||||
|
||||
Run the test with C<prove> like this:
|
||||
|
||||
prove test/test.t
|
||||
|
||||
Prove knows it's Bash from the first line (the hashbang), and it just works.
|
||||
|
||||
=head1 Description
|
||||
|
||||
Test::More is the tried and true testing library for Perl. It uses TAP (the
|
||||
Test Anything Protocol). This is the same thing for Bash. For the most part it
|
||||
should work exactly the same.
|
||||
|
||||
=head1 Methods
|
||||
|
||||
This is the basic usage:
|
||||
|
||||
=over
|
||||
|
||||
=item * C<plan tests $count>
|
||||
|
||||
=item * C<ok $status_code "$label">
|
||||
|
||||
=item * C<pass "$label">
|
||||
|
||||
=item * C<fail "$label">
|
||||
|
||||
=item * C<is "$got" "$want" "label">
|
||||
|
||||
=item * C<isnt "$got" "$unwanted" "$label">
|
||||
|
||||
=item * C<like "$got" "$regex" "$label">
|
||||
|
||||
=item * C<unlike "$got" "$regex" "$label">
|
||||
|
||||
=item * C<diag "$message">
|
||||
|
||||
=item * C<note "$message">
|
||||
|
||||
=item * C<done_testing $count>
|
||||
|
||||
=item * C<plan skip_all "$reason">
|
||||
|
||||
=item * C<BAIL_OUT "$reason">
|
||||
|
||||
=back
|
||||
|
||||
More detailed info coming soon.
|
||||
|
||||
=head1 Author
|
||||
|
||||
Ingy döt Net <ingy@bpan.org>
|
||||
|
||||
=head1 Copyright & License
|
||||
|
||||
Copyright 2013-2016. Ingy döt Net.
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
=cut
|
||||
89
build/git-subrepo/ext/test-more-bash/doc/test-more.swim
Normal file
89
build/git-subrepo/ext/test-more-bash/doc/test-more.swim
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
Test::More
|
||||
==========
|
||||
|
||||
TAP Testing for Bash
|
||||
|
||||
<badge travis ingydotnet/test-more-bash>
|
||||
|
||||
= Synopsis
|
||||
|
||||
Write a test file like this. Maybe call it `test/test.t`:
|
||||
|
||||
#!/usr/bin/env bash
|
||||
|
||||
TEST_MORE_PATH="/path/to/test-more-bash"
|
||||
BASHLIB="`
|
||||
find $TEST_MORE_PATH -type d |
|
||||
grep -E '/(bin|lib)$' |
|
||||
xargs -n1 printf "%s:"`"
|
||||
PATH="$BASHLIB$PATH"
|
||||
|
||||
source bash+ :std
|
||||
|
||||
use Test::More
|
||||
|
||||
plan tests 8
|
||||
|
||||
some-command
|
||||
ok $? 'some-command is ok'
|
||||
|
||||
# or:
|
||||
ok "`some-command`" 'some-command is ok'
|
||||
|
||||
pass 'This will always pass'
|
||||
|
||||
fail 'This will always fail'
|
||||
|
||||
is `echo foo` 'foo' 'foo is foo'
|
||||
|
||||
isnt foo bar "foo isn't bar"
|
||||
|
||||
like food foo 'food is like foo'
|
||||
|
||||
unlike team I "There's no 'I' in 'team'"
|
||||
|
||||
diag "A message for stderr"
|
||||
|
||||
note "A message for stdout"
|
||||
|
||||
Run the test with `prove` like this:
|
||||
|
||||
prove test/test.t
|
||||
|
||||
Prove knows it's Bash from the first line (the hashbang), and it just works.
|
||||
|
||||
= Description
|
||||
|
||||
Test::More is the tried and true testing library for Perl. It uses TAP (the
|
||||
Test Anything Protocol). This is the same thing for Bash. For the most part it
|
||||
should work exactly the same.
|
||||
|
||||
= Methods
|
||||
|
||||
This is the basic usage:
|
||||
|
||||
* `plan tests $count`
|
||||
* `ok $status_code "$label"`
|
||||
* `pass "$label"`
|
||||
* `fail "$label"`
|
||||
* `is "$got" "$want" "label"`
|
||||
* `isnt "$got" "$unwanted" "$label"`
|
||||
* `like "$got" "$regex" "$label"`
|
||||
* `unlike "$got" "$regex" "$label"`
|
||||
* `diag "$message"`
|
||||
* `note "$message"`
|
||||
* `done_testing $count`
|
||||
* `plan skip_all "$reason"`
|
||||
* `BAIL_OUT "$reason"`
|
||||
|
||||
More detailed info coming soon.
|
||||
|
||||
= Author
|
||||
|
||||
Ingy döt Net <ingy@bpan.org>
|
||||
|
||||
= Copyright & License
|
||||
|
||||
Copyright 2013-2016. Ingy döt Net.
|
||||
|
||||
The MIT License (MIT)
|
||||
0
build/git-subrepo/ext/test-more-bash/ext/bashplus/.gitignore
vendored
Normal file
0
build/git-subrepo/ext/test-more-bash/ext/bashplus/.gitignore
vendored
Normal file
11
build/git-subrepo/ext/test-more-bash/ext/bashplus/.gitrepo
Normal file
11
build/git-subrepo/ext/test-more-bash/ext/bashplus/.gitrepo
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
; DO NOT EDIT (unless you know what you are doing)
|
||||
;
|
||||
; This subdirectory is a git "subrepo", and this file is maintained by the
|
||||
; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
|
||||
;
|
||||
[subrepo]
|
||||
remote = git@github.com:ingydotnet/bashplus.git
|
||||
branch = master
|
||||
commit = d9183af6f46946fabdef1dd8f37824c042a378f8
|
||||
parent = 05a1bddbe237bbf2c390048c80ca70d4f66c6a37
|
||||
cmdver = 0.3.0
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
# C language gives closest shell env.
|
||||
language: c
|
||||
|
||||
script:
|
||||
- git submodule update --init --recursive
|
||||
- PROVEOPT=-v make test
|
||||
15
build/git-subrepo/ext/test-more-bash/ext/bashplus/Changes
Normal file
15
build/git-subrepo/ext/test-more-bash/ext/bashplus/Changes
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
version: 0.0.7
|
||||
date: Sat Jan 23 16:28:59 PST 2016
|
||||
changes:
|
||||
- Update tooling, and copyright
|
||||
---
|
||||
version: 0.0.6
|
||||
date: Fri Jan 23 21:05:15 PST 2015
|
||||
changes:
|
||||
- Update tooling, and copyright
|
||||
---
|
||||
version: 0.0.1
|
||||
date: Sun Oct 27 19:07:51 PDT 2013
|
||||
changes:
|
||||
- First release.
|
||||
21
build/git-subrepo/ext/test-more-bash/ext/bashplus/License
Normal file
21
build/git-subrepo/ext/test-more-bash/ext/bashplus/License
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
(The MIT License)
|
||||
|
||||
Copyright © 2013-2016 Ingy döt Net
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the ‘Software’), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
45
build/git-subrepo/ext/test-more-bash/ext/bashplus/Makefile
Normal file
45
build/git-subrepo/ext/test-more-bash/ext/bashplus/Makefile
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
ifeq ($(MAKECMDGOALS),install)
|
||||
ifeq "$(shell bpan version 2>/dev/null)" ""
|
||||
$(error 'BPAN not installed. See http://bpan.org')
|
||||
endif
|
||||
endif
|
||||
|
||||
NAME := bash+
|
||||
LIB := lib/$(NAME).bash
|
||||
DOC := doc/$(NAME).swim
|
||||
MAN1 := man/man1
|
||||
MAN3 := man/man3
|
||||
|
||||
INSTALL_LIB ?= $(shell bpan env BPAN_LIB)
|
||||
INSTALL_DIR ?= test
|
||||
INSTALL_MAN1 ?= $(shell bpan env BPAN_MAN1)
|
||||
INSTALL_MAN3 ?= $(shell bpan env BPAN_MAN3)
|
||||
|
||||
default: help
|
||||
|
||||
help:
|
||||
@echo 'Rules: test, install, doc'
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
prove $(PROVEOPT:%=% )test/
|
||||
|
||||
install:
|
||||
install -C -d -m 0755 $(INSTALL_LIB)/$(INSTALL_DIR)/
|
||||
install -C -m 0755 $(LIB) $(INSTALL_LIB)/$(INSTALL_DIR)/
|
||||
install -C -d -m 0755 $(INSTALL_MAN1)/
|
||||
install -C -d -m 0755 $(INSTALL_MAN3)/
|
||||
install -C -m 0644 $(MAN1)/$(NAME).1 $(INSTALL_MAN1)/
|
||||
install -C -m 0644 $(MAN3)/$(NAME).3 $(INSTALL_MAN3)/
|
||||
|
||||
.PHONY: doc
|
||||
doc: ReadMe.pod $(MAN1)/$(NAME).1 $(MAN3)/$(NAME).3
|
||||
|
||||
ReadMe.pod: $(DOC)
|
||||
swim --to=pod --complete --wrap $< > $@
|
||||
|
||||
$(MAN1)/%.1: doc/%.swim
|
||||
swim --to=man $< > $@
|
||||
|
||||
$(MAN3)/%.3: doc/%.swim
|
||||
swim --to=man $< > $@
|
||||
28
build/git-subrepo/ext/test-more-bash/ext/bashplus/Meta
Normal file
28
build/git-subrepo/ext/test-more-bash/ext/bashplus/Meta
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
=meta: 0.0.2
|
||||
|
||||
name: bashplus
|
||||
version: 0.0.7
|
||||
abstract: Modern Bash Programming
|
||||
homepage: http://bpan.org/package/bashplus/
|
||||
|
||||
license: MIT
|
||||
copyright: 2013-2016
|
||||
author:
|
||||
name: Ingy döt Net
|
||||
email: ingy@ingy.net
|
||||
github: ingydotnet
|
||||
twitter: ingydotnet
|
||||
freenode: ingy
|
||||
homepage: http://ingy.net
|
||||
|
||||
requires:
|
||||
bash: 3.2.0
|
||||
test:
|
||||
cmd: make test
|
||||
install:
|
||||
cmd: make install
|
||||
|
||||
devel:
|
||||
git: git@github.org/ingydotnet/bashplus
|
||||
irc: irc.freenode.net/bpan
|
||||
bug: https://github.com/ingydotnet/bashplus/issues/
|
||||
77
build/git-subrepo/ext/test-more-bash/ext/bashplus/ReadMe.pod
Normal file
77
build/git-subrepo/ext/test-more-bash/ext/bashplus/ReadMe.pod
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
=pod
|
||||
|
||||
=for comment
|
||||
DO NOT EDIT. This Pod was generated by Swim v0.1.41.
|
||||
See http://github.com/ingydotnet/swim-pm#readme
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 Name
|
||||
|
||||
Bash+(1) - Modern Bash Programming
|
||||
|
||||
=for html
|
||||
<a href="https://travis-ci.org/ingydotnet/bashplus"><img src="https://travis-ci.org/ingydotnet/bashplus.png" alt="bashplus"></a>
|
||||
|
||||
=head1 Synopsis
|
||||
|
||||
source bash+ :std :array
|
||||
|
||||
use Foo::Bar this that
|
||||
|
||||
Array.new args "$@"
|
||||
|
||||
if args.empty?; then
|
||||
die "I need args!"
|
||||
fi
|
||||
|
||||
Foo::Bar.new foo args
|
||||
|
||||
this is awesome # <= this is a real command! (You just imported it)
|
||||
|
||||
=head1 Description
|
||||
|
||||
Bash+ is just Bash... B<plus> some libraries that can make Bash programming a
|
||||
lot nicer.
|
||||
|
||||
=for comment # Installation
|
||||
|
||||
Get the source code from GitHub:
|
||||
|
||||
git clone git@github.com:ingydotnet/bashplus
|
||||
|
||||
Then run:
|
||||
|
||||
make test
|
||||
make install # Possibly with 'sudo'
|
||||
|
||||
=head1 Usage
|
||||
|
||||
For now look at some libraries the use Bash+:
|
||||
|
||||
=over
|
||||
|
||||
=item * L<https://github.com/ingydotnet/git-hub>
|
||||
|
||||
=item * L<https://github.com/ingydotnet/json-bash>
|
||||
|
||||
=item * L<https://github.com/ingydotnet/test-more-bash>
|
||||
|
||||
=back
|
||||
|
||||
=head1 Status
|
||||
|
||||
If you are interested in chatting about this, C</join #bpan> on
|
||||
irc.freenode.net.
|
||||
|
||||
=head1 Author
|
||||
|
||||
Written by Ingy döt Net <ingy@ingy.net>
|
||||
|
||||
=head1 Copyright & License
|
||||
|
||||
Copyright 2013-2016. Ingy döt Net.
|
||||
|
||||
The MIT License (MIT).
|
||||
|
||||
=cut
|
||||
43
build/git-subrepo/ext/test-more-bash/ext/bashplus/bin/bash+
Normal file
43
build/git-subrepo/ext/test-more-bash/ext/bashplus/bin/bash+
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env bash
|
||||
#------------------------------------------------------------------------------
|
||||
# Bash+ - Modern Bash Programming
|
||||
#
|
||||
# Copyright (c) 2013-2016 Ingy döt Net
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
set -e
|
||||
shopt -s compat31&>/dev/null||:
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Determine how `bash+` was called, and do the right thing:
|
||||
#------------------------------------------------------------------------------
|
||||
if [ "${BASH_SOURCE[0]}" != "$0" ]; then
|
||||
# 'bash+' is being sourced:
|
||||
[[ "${BASH_SOURCE[0]}" =~ /bin/bash\\+$ ]] || {
|
||||
echo "Invalid Bash+ path '${BASH_SOURCE[0]}'" 2> /dev/null
|
||||
exit 1
|
||||
}
|
||||
source "${BASH_SOURCE[0]%/bin/*}"/lib/bash+.bash || return $?
|
||||
bash+:import "$@"
|
||||
return $?
|
||||
else
|
||||
if [ $# -eq 1 -a "$1" == --version ]; then
|
||||
echo 'bash+ version 0.0.7'
|
||||
else
|
||||
cat <<...
|
||||
|
||||
Greetings modern Bash programmer. Welcome to Bash+!
|
||||
|
||||
Bash+ is framework that makes Bash programming more like Ruby and Perl.
|
||||
|
||||
See: https://github.com/bpan-org/bashplus
|
||||
|
||||
If you got here trying to use bash+ in a program, you need to source it:
|
||||
|
||||
source bash+
|
||||
|
||||
Happy Bash Hacking!
|
||||
|
||||
...
|
||||
fi
|
||||
fi
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
Bash+(1)
|
||||
========
|
||||
|
||||
Modern Bash Programming
|
||||
|
||||
<badge travis ingydotnet/bashplus>
|
||||
|
||||
= Synopsis
|
||||
|
||||
source bash+ :std :array
|
||||
|
||||
use Foo::Bar this that
|
||||
|
||||
Array.new args "$@"
|
||||
|
||||
if args.empty?; then
|
||||
die "I need args!"
|
||||
fi
|
||||
|
||||
Foo::Bar.new foo args
|
||||
|
||||
this is awesome # <= this is a real command! (You just imported it)
|
||||
|
||||
= Description
|
||||
|
||||
Bash+ is just Bash... *plus* some libraries that can make Bash programming a
|
||||
lot nicer.
|
||||
|
||||
## Installation
|
||||
|
||||
Get the source code from GitHub:
|
||||
|
||||
git clone git@github.com:ingydotnet/bashplus
|
||||
|
||||
Then run:
|
||||
|
||||
make test
|
||||
make install # Possibly with 'sudo'
|
||||
|
||||
= Usage
|
||||
|
||||
For now look at some libraries the use Bash+:
|
||||
|
||||
* https://github.com/ingydotnet/git-hub
|
||||
* https://github.com/ingydotnet/json-bash
|
||||
* https://github.com/ingydotnet/test-more-bash
|
||||
|
||||
= Status
|
||||
|
||||
If you are interested in chatting about this, `/join #bpan` on
|
||||
irc.freenode.net.
|
||||
|
||||
= Author
|
||||
|
||||
Written by Ingy döt Net <ingy@ingy.net>
|
||||
|
||||
= Copyright & License
|
||||
|
||||
Copyright 2013-2016. Ingy döt Net.
|
||||
|
||||
The MIT License (MIT).
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28)
|
||||
.\"
|
||||
.\" Standard preamble:
|
||||
.\" ========================================================================
|
||||
.de Sp \" Vertical space (when we can't use .PP)
|
||||
.if t .sp .5v
|
||||
.if n .sp
|
||||
..
|
||||
.de Vb \" Begin verbatim text
|
||||
.ft CW
|
||||
.nf
|
||||
.ne \\$1
|
||||
..
|
||||
.de Ve \" End verbatim text
|
||||
.ft R
|
||||
.fi
|
||||
..
|
||||
.\" Set up some character translations and predefined strings. \*(-- will
|
||||
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
|
||||
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
|
||||
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
|
||||
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
|
||||
.\" nothing in troff, for use with C<>.
|
||||
.tr \(*W-
|
||||
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
|
||||
.ie n \{\
|
||||
. ds -- \(*W-
|
||||
. ds PI pi
|
||||
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
|
||||
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
|
||||
. ds L" ""
|
||||
. ds R" ""
|
||||
. ds C` ""
|
||||
. ds C' ""
|
||||
'br\}
|
||||
.el\{\
|
||||
. ds -- \|\(em\|
|
||||
. ds PI \(*p
|
||||
. ds L" ``
|
||||
. ds R" ''
|
||||
. ds C`
|
||||
. ds C'
|
||||
'br\}
|
||||
.\"
|
||||
.\" Escape single quotes in literal strings from groff's Unicode transform.
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\"
|
||||
.\" If the F register is turned on, we'll generate index entries on stderr for
|
||||
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
|
||||
.\" entries marked with X<> in POD. Of course, you'll have to process the
|
||||
.\" output yourself in some meaningful fashion.
|
||||
.\"
|
||||
.\" Avoid warning from groff about undefined register 'F'.
|
||||
.de IX
|
||||
..
|
||||
.nr rF 0
|
||||
.if \n(.g .if rF .nr rF 1
|
||||
.if (\n(rF:(\n(.g==0)) \{
|
||||
. if \nF \{
|
||||
. de IX
|
||||
. tm Index:\\$1\t\\n%\t"\\$2"
|
||||
..
|
||||
. if !\nF==2 \{
|
||||
. nr % 0
|
||||
. nr F 2
|
||||
. \}
|
||||
. \}
|
||||
.\}
|
||||
.rr rF
|
||||
.\" ========================================================================
|
||||
.\"
|
||||
.IX Title "Bash+(1) 1"
|
||||
.TH Bash+(1) 1 "January 2016" "Generated by Swim v0.1.41" "Modern Bash Programming"
|
||||
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
||||
.\" way too many mistakes in technical documents.
|
||||
.if n .ad l
|
||||
.nh
|
||||
.SH "Name"
|
||||
.IX Header "Name"
|
||||
Bash+(1) \- Modern Bash Programming
|
||||
.SH "Synopsis"
|
||||
.IX Header "Synopsis"
|
||||
.Vb 1
|
||||
\& source bash+ :std :array
|
||||
\&
|
||||
\& use Foo::Bar this that
|
||||
\&
|
||||
\& Array.new args "$@"
|
||||
\&
|
||||
\& if args.empty?; then
|
||||
\& die "I need args!"
|
||||
\& fi
|
||||
\&
|
||||
\& Foo::Bar.new foo args
|
||||
\&
|
||||
\& this is awesome # <= this is a real command! (You just imported it)
|
||||
.Ve
|
||||
.SH "Description"
|
||||
.IX Header "Description"
|
||||
Bash+ is just Bash... \fBplus\fR some libraries that can make Bash programming a lot nicer.
|
||||
.PP
|
||||
Get the source code from GitHub:
|
||||
.PP
|
||||
.Vb 1
|
||||
\& git clone git@github.com:ingydotnet/bashplus
|
||||
.Ve
|
||||
.PP
|
||||
Then run:
|
||||
.PP
|
||||
.Vb 2
|
||||
\& make test
|
||||
\& make install # Possibly with \*(Aqsudo\*(Aq
|
||||
.Ve
|
||||
.SH "Usage"
|
||||
.IX Header "Usage"
|
||||
For now look at some libraries the use Bash+:
|
||||
.IP "\(bu" 4
|
||||
<https://github.com/ingydotnet/git\-hub>
|
||||
.IP "\(bu" 4
|
||||
<https://github.com/ingydotnet/json\-bash>
|
||||
.IP "\(bu" 4
|
||||
<https://github.com/ingydotnet/test\-more\-bash>
|
||||
.SH "Status"
|
||||
.IX Header "Status"
|
||||
If you are interested in chatting about this, \f(CW\*(C`/join #bpan\*(C'\fR on irc.freenode.net.
|
||||
.SH "Author"
|
||||
.IX Header "Author"
|
||||
Written by Ingy döt Net <ingy@ingy.net>
|
||||
.SH "Copyright & License"
|
||||
.IX Header "Copyright & License"
|
||||
Copyright 2013\-2016. Ingy döt Net.
|
||||
.PP
|
||||
The \s-1MIT\s0 License (\s-1MIT\s0).
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28)
|
||||
.\"
|
||||
.\" Standard preamble:
|
||||
.\" ========================================================================
|
||||
.de Sp \" Vertical space (when we can't use .PP)
|
||||
.if t .sp .5v
|
||||
.if n .sp
|
||||
..
|
||||
.de Vb \" Begin verbatim text
|
||||
.ft CW
|
||||
.nf
|
||||
.ne \\$1
|
||||
..
|
||||
.de Ve \" End verbatim text
|
||||
.ft R
|
||||
.fi
|
||||
..
|
||||
.\" Set up some character translations and predefined strings. \*(-- will
|
||||
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
|
||||
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
|
||||
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
|
||||
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
|
||||
.\" nothing in troff, for use with C<>.
|
||||
.tr \(*W-
|
||||
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
|
||||
.ie n \{\
|
||||
. ds -- \(*W-
|
||||
. ds PI pi
|
||||
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
|
||||
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
|
||||
. ds L" ""
|
||||
. ds R" ""
|
||||
. ds C` ""
|
||||
. ds C' ""
|
||||
'br\}
|
||||
.el\{\
|
||||
. ds -- \|\(em\|
|
||||
. ds PI \(*p
|
||||
. ds L" ``
|
||||
. ds R" ''
|
||||
. ds C`
|
||||
. ds C'
|
||||
'br\}
|
||||
.\"
|
||||
.\" Escape single quotes in literal strings from groff's Unicode transform.
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\"
|
||||
.\" If the F register is turned on, we'll generate index entries on stderr for
|
||||
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
|
||||
.\" entries marked with X<> in POD. Of course, you'll have to process the
|
||||
.\" output yourself in some meaningful fashion.
|
||||
.\"
|
||||
.\" Avoid warning from groff about undefined register 'F'.
|
||||
.de IX
|
||||
..
|
||||
.nr rF 0
|
||||
.if \n(.g .if rF .nr rF 1
|
||||
.if (\n(rF:(\n(.g==0)) \{
|
||||
. if \nF \{
|
||||
. de IX
|
||||
. tm Index:\\$1\t\\n%\t"\\$2"
|
||||
..
|
||||
. if !\nF==2 \{
|
||||
. nr % 0
|
||||
. nr F 2
|
||||
. \}
|
||||
. \}
|
||||
.\}
|
||||
.rr rF
|
||||
.\" ========================================================================
|
||||
.\"
|
||||
.IX Title "Bash+(1) 1"
|
||||
.TH Bash+(1) 1 "January 2016" "Generated by Swim v0.1.41" "Modern Bash Programming"
|
||||
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
||||
.\" way too many mistakes in technical documents.
|
||||
.if n .ad l
|
||||
.nh
|
||||
.SH "Name"
|
||||
.IX Header "Name"
|
||||
Bash+(1) \- Modern Bash Programming
|
||||
.SH "Synopsis"
|
||||
.IX Header "Synopsis"
|
||||
.Vb 1
|
||||
\& source bash+ :std :array
|
||||
\&
|
||||
\& use Foo::Bar this that
|
||||
\&
|
||||
\& Array.new args "$@"
|
||||
\&
|
||||
\& if args.empty?; then
|
||||
\& die "I need args!"
|
||||
\& fi
|
||||
\&
|
||||
\& Foo::Bar.new foo args
|
||||
\&
|
||||
\& this is awesome # <= this is a real command! (You just imported it)
|
||||
.Ve
|
||||
.SH "Description"
|
||||
.IX Header "Description"
|
||||
Bash+ is just Bash... \fBplus\fR some libraries that can make Bash programming a lot nicer.
|
||||
.PP
|
||||
Get the source code from GitHub:
|
||||
.PP
|
||||
.Vb 1
|
||||
\& git clone git@github.com:ingydotnet/bashplus
|
||||
.Ve
|
||||
.PP
|
||||
Then run:
|
||||
.PP
|
||||
.Vb 2
|
||||
\& make test
|
||||
\& make install # Possibly with \*(Aqsudo\*(Aq
|
||||
.Ve
|
||||
.SH "Usage"
|
||||
.IX Header "Usage"
|
||||
For now look at some libraries the use Bash+:
|
||||
.IP "\(bu" 4
|
||||
<https://github.com/ingydotnet/git\-hub>
|
||||
.IP "\(bu" 4
|
||||
<https://github.com/ingydotnet/json\-bash>
|
||||
.IP "\(bu" 4
|
||||
<https://github.com/ingydotnet/test\-more\-bash>
|
||||
.SH "Status"
|
||||
.IX Header "Status"
|
||||
If you are interested in chatting about this, \f(CW\*(C`/join #bpan\*(C'\fR on irc.freenode.net.
|
||||
.SH "Author"
|
||||
.IX Header "Author"
|
||||
Written by Ingy döt Net <ingy@ingy.net>
|
||||
.SH "Copyright & License"
|
||||
.IX Header "Copyright & License"
|
||||
Copyright 2013\-2016. Ingy döt Net.
|
||||
.PP
|
||||
The \s-1MIT\s0 License (\s-1MIT\s0).
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
source test/test.bash
|
||||
|
||||
PATH=$PWD/bin:$PATH
|
||||
source bash+ :std
|
||||
|
||||
ok $? '`source bash+` works'
|
||||
|
||||
is "$BASHPLUS_VERSION" '0.0.7' 'BASHPLUS_VERSION is 0.0.7'
|
||||
|
||||
done_testing 2
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
source test/test.bash
|
||||
|
||||
PATH=$PWD/bin:$PATH
|
||||
source bash+
|
||||
|
||||
foo() {
|
||||
echo O HAI
|
||||
}
|
||||
|
||||
like "$(type bar 2>&1)" 'bar: not found' \
|
||||
'bar is not yet a function'
|
||||
|
||||
bash+:fcopy foo bar
|
||||
|
||||
type -t bar &>/dev/null
|
||||
ok $? 'bar is now a function'
|
||||
is "$(type foo | tail -n+3)" "$(type bar | tail -n+3)" \
|
||||
'Copy matches original'
|
||||
|
||||
done_testing 3
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
source test/test.bash
|
||||
|
||||
PATH=$PWD/bin:$PATH
|
||||
source bash+ :std
|
||||
|
||||
ok "`bash+:can use`" 'use is imported'
|
||||
ok "`bash+:can die`" 'die is imported'
|
||||
ok "`bash+:can warn`" 'warn is imported'
|
||||
|
||||
ok "`! bash+:can import`" 'import is not imported'
|
||||
ok "`! bash+:can main`" 'main is not imported'
|
||||
ok "`! bash+:can fcopy`" 'fcopy is not imported'
|
||||
ok "`! bash+:can findlib`" 'findlib is not imported'
|
||||
ok "`! bash+:can can`" 'can is not imported'
|
||||
|
||||
done_testing 8
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
source test/test.bash
|
||||
|
||||
PATH=$PWD/bin:$PATH
|
||||
source bash+
|
||||
|
||||
functions=(
|
||||
use
|
||||
import
|
||||
fcopy
|
||||
findlib
|
||||
die
|
||||
warn
|
||||
can
|
||||
)
|
||||
|
||||
for f in ${functions[@]}; do
|
||||
is "$(type -t "bash+:$f")" function \
|
||||
"bash+:$f is a function"
|
||||
done
|
||||
|
||||
done_testing 7
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# This is a tiny version of test-more-bash that I use here. test-more-bash uses
|
||||
# bash+, so I want to avoid the circular dependency. This little guy does
|
||||
# 80-90% what test-more-bash does, with minimal code. It's a good example of
|
||||
# how nice Bash can be.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
plan() {
|
||||
echo "1..$1"
|
||||
}
|
||||
|
||||
pass() {
|
||||
let run=run+1
|
||||
echo "ok $run${1:+ - $1}"
|
||||
}
|
||||
|
||||
fail() {
|
||||
let run=run+1
|
||||
echo "not ok $run${1:+ - $1}"
|
||||
}
|
||||
|
||||
is() {
|
||||
if [ "$1" == "$2" ]; then
|
||||
pass "$3"
|
||||
else
|
||||
fail "$3"
|
||||
diag "Got: $1"
|
||||
diag "Want: $2"
|
||||
fi
|
||||
}
|
||||
|
||||
ok() {
|
||||
(exit ${1:-$?}) &&
|
||||
pass "$2" ||
|
||||
fail "$2"
|
||||
}
|
||||
|
||||
like() {
|
||||
if [[ "$1" =~ "$2" ]]; then
|
||||
pass "$3"
|
||||
else
|
||||
fail "$3"
|
||||
diag "Got: $1"
|
||||
diag "Like: $2"
|
||||
fi
|
||||
}
|
||||
|
||||
unlike() {
|
||||
if [[ ! "$1" =~ "$2" ]]; then
|
||||
pass "$3"
|
||||
else
|
||||
fail "$3"
|
||||
diag "Got: $1"
|
||||
diag "Dont: $2"
|
||||
fi
|
||||
}
|
||||
|
||||
done_testing() {
|
||||
echo "1..${1:-$run}"
|
||||
}
|
||||
|
||||
diag() {
|
||||
echo "# ${1//$'\n'/$'\n'# }" >&2
|
||||
}
|
||||
|
||||
note() {
|
||||
echo "# ${1//$'\n'/$'\n'# }"
|
||||
}
|
||||
19
build/git-subrepo/ext/test-more-bash/ext/bashplus/test/use.t
Normal file
19
build/git-subrepo/ext/test-more-bash/ext/bashplus/test/use.t
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
source test/test.bash
|
||||
|
||||
PATH=$PWD/bin:$PATH
|
||||
source bash+ :std can
|
||||
|
||||
BASHLIB=test/lib
|
||||
|
||||
use Foo::Bar
|
||||
ok $? 'use Foo::Bar - works'
|
||||
ok "`can Foo::Bar:baz`" 'Function Foo::Bar:baz exists'
|
||||
is "$Foo__Bar_VERSION" 1.2.3 '$Foo__Bar_VERSION == 1.2.3'
|
||||
|
||||
output=`use Foo::Foo Boo Booo`
|
||||
ok $? 'use Foo::Foo Boo Booo - works'
|
||||
is "$output" Boo---Booo 'Correct import called'
|
||||
|
||||
done_testing 5
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
; DO NOT EDIT (unless you know what you are doing)
|
||||
;
|
||||
; This subdirectory is a git "subrepo", and this file is maintained by the
|
||||
; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
|
||||
;
|
||||
[subrepo]
|
||||
remote = git@github.com:ingydotnet/test-tap-bash.git
|
||||
branch = master
|
||||
commit = 7890df93f13e684715750a2d6a608e7e79671ca4
|
||||
parent = 3faca582ee96a320b5675ad67b47ad0f16730446
|
||||
cmdver = 0.3.0
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
# C language gives closest shell env.
|
||||
language: c
|
||||
|
||||
script:
|
||||
- git submodule update --init --recursive
|
||||
- PROVEOPT=-v make test
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
version: 0.0.4
|
||||
date: Sat Jan 23 16:32:22 PST 2016
|
||||
changes:
|
||||
- Make up to date.
|
||||
---
|
||||
version: 0.0.3
|
||||
date: Fri Jan 23 21:39:39 PST 2015
|
||||
changes:
|
||||
- Make up to date.
|
||||
---
|
||||
version: 0.0.1
|
||||
date: Sun Oct 27 23:02:11 PDT 2013
|
||||
changes:
|
||||
- First release.
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
(The MIT License)
|
||||
|
||||
Copyright © 2013-2016. Ingy döt Net.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the ‘Software’), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
ifeq ($(MAKECMDGOALS),install)
|
||||
ifeq "$(shell bpan version 2>/dev/null)" ""
|
||||
$(error 'BPAN not installed. See http://bpan.org')
|
||||
endif
|
||||
endif
|
||||
|
||||
NAME := test-tap
|
||||
LIB := lib/test/tap.bash
|
||||
MAN3 := man/man3
|
||||
|
||||
INSTALL_LIB ?= $(shell bpan env BPAN_LIB)
|
||||
INSTALL_DIR ?= test
|
||||
INSTALL_MAN3 ?= $(shell bpan env BPAN_MAN3)
|
||||
|
||||
default: help
|
||||
|
||||
help:
|
||||
@echo 'Rules: test, install, doc'
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
prove $(PROVEOPT:%=% )test/
|
||||
|
||||
install:
|
||||
install -C -d -m 0755 $(INSTALL_LIB)/$(INSTALL_DIR)/
|
||||
install -C -m 0755 $(LIB) $(INSTALL_LIB)/$(INSTALL_DIR)/
|
||||
install -C -d -m 0755 $(INSTALL_MAN3)/
|
||||
install -C -m 0644 $(MAN3)/$(NAME).3 $(INSTALL_MAN3)/
|
||||
|
||||
.PHONY: doc
|
||||
doc: ReadMe.pod $(MAN3)/$(NAME).3
|
||||
|
||||
ReadMe.pod: doc/test-tap.swim
|
||||
swim --to=pod --complete --wrap $< > $@
|
||||
|
||||
man/man3/%.3: doc/%.swim
|
||||
swim --to=man $< > $@
|
||||
28
build/git-subrepo/ext/test-more-bash/ext/test-tap-bash/Meta
Normal file
28
build/git-subrepo/ext/test-more-bash/ext/test-tap-bash/Meta
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
=meta: 0.0.2
|
||||
|
||||
name: test-tap
|
||||
version: 0.0.4
|
||||
abstract: TAP Test Base for Bash
|
||||
homepage: http://bpan.org/package/test-tap/
|
||||
|
||||
license: MIT
|
||||
copyright: 2013-2016
|
||||
author:
|
||||
name: Ingy döt Net
|
||||
email: ingy@ingy.net
|
||||
github: ingydotnet
|
||||
twitter: ingydotnet
|
||||
freenode: ingy
|
||||
homepage: http://ingy.net
|
||||
|
||||
requires:
|
||||
bash: 3.2.0
|
||||
test:
|
||||
cmd: make test
|
||||
install:
|
||||
cmd: make install
|
||||
|
||||
devel:
|
||||
git: git@github.org/ingydotnet/test-tap-bash.git
|
||||
irc: irc.freenode.net/bpan
|
||||
bug: https://github.com/ingydotnet/test-tap-bash/issues/
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
=pod
|
||||
|
||||
=for comment
|
||||
DO NOT EDIT. This Pod was generated by Swim v0.1.41.
|
||||
See http://github.com/ingydotnet/swim-pm#readme
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 Name
|
||||
|
||||
Test::Tap - TAP Test Base for Bash
|
||||
|
||||
=for html
|
||||
<a href="https://travis-ci.org/ingydotnet/test-tap-bash"><img src="https://travis-ci.org/ingydotnet/test-tap-bash.png" alt="test-tap-bash"></a>
|
||||
|
||||
=head1 Synopsis
|
||||
|
||||
source test/tap.bash
|
||||
|
||||
Test::Tap:plan tests 1
|
||||
|
||||
pass 'Everything is OK!'
|
||||
|
||||
=head1 Description
|
||||
|
||||
This is a TAP testing base class for Bash. It has all the basic TAP functions,
|
||||
and works properly from a TAP harness, like the C<prove> utility.
|
||||
|
||||
test-tap-bash is used as the base for test-more-bash, which is what you want
|
||||
if you are writing tests in bash.
|
||||
|
||||
See: L<https://github.com/ingydotnet/test-more-bash/>
|
||||
|
||||
=head1 Functions
|
||||
|
||||
=over
|
||||
|
||||
=item C<Test::Tap:init>
|
||||
|
||||
Must be called first for every test file/process.
|
||||
|
||||
=item C<Test::Tap::plan>
|
||||
|
||||
Used to set the plan.
|
||||
|
||||
=back
|
||||
|
||||
=head1 TODO
|
||||
|
||||
=over
|
||||
|
||||
=item * Finish this doc.
|
||||
|
||||
=back
|
||||
|
||||
=head1 Author
|
||||
|
||||
Written by Ingy döt Net <ingy@ingy.net>
|
||||
|
||||
=head1 Copyright & License
|
||||
|
||||
Copyright 2013-2016. Ingy döt Net.
|
||||
|
||||
The MIT License (MIT).
|
||||
|
||||
=cut
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
Test::Tap
|
||||
=========
|
||||
|
||||
TAP Test Base for Bash
|
||||
|
||||
<badge travis ingydotnet/test-tap-bash>
|
||||
|
||||
= Synopsis
|
||||
|
||||
source test/tap.bash
|
||||
|
||||
Test::Tap:plan tests 1
|
||||
|
||||
pass 'Everything is OK!'
|
||||
|
||||
= Description
|
||||
|
||||
This is a TAP testing base class for Bash. It has all the basic TAP functions,
|
||||
and works properly from a TAP harness, like the `prove` utility.
|
||||
|
||||
test-tap-bash is used as the base for test-more-bash, which is what you want
|
||||
if you are writing tests in bash.
|
||||
|
||||
See: https://github.com/ingydotnet/test-more-bash/
|
||||
|
||||
= Functions
|
||||
|
||||
- `Test::Tap:init`
|
||||
|
||||
Must be called first for every test file/process.
|
||||
|
||||
- `Test::Tap::plan`
|
||||
|
||||
Used to set the plan.
|
||||
|
||||
= TODO
|
||||
|
||||
* Finish this doc.
|
||||
|
||||
= Author
|
||||
|
||||
Written by Ingy döt Net <ingy@ingy.net>
|
||||
|
||||
= Copyright & License
|
||||
|
||||
Copyright 2013-2016. Ingy döt Net.
|
||||
|
||||
The MIT License (MIT).
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28)
|
||||
.\"
|
||||
.\" Standard preamble:
|
||||
.\" ========================================================================
|
||||
.de Sp \" Vertical space (when we can't use .PP)
|
||||
.if t .sp .5v
|
||||
.if n .sp
|
||||
..
|
||||
.de Vb \" Begin verbatim text
|
||||
.ft CW
|
||||
.nf
|
||||
.ne \\$1
|
||||
..
|
||||
.de Ve \" End verbatim text
|
||||
.ft R
|
||||
.fi
|
||||
..
|
||||
.\" Set up some character translations and predefined strings. \*(-- will
|
||||
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
|
||||
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
|
||||
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
|
||||
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
|
||||
.\" nothing in troff, for use with C<>.
|
||||
.tr \(*W-
|
||||
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
|
||||
.ie n \{\
|
||||
. ds -- \(*W-
|
||||
. ds PI pi
|
||||
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
|
||||
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
|
||||
. ds L" ""
|
||||
. ds R" ""
|
||||
. ds C` ""
|
||||
. ds C' ""
|
||||
'br\}
|
||||
.el\{\
|
||||
. ds -- \|\(em\|
|
||||
. ds PI \(*p
|
||||
. ds L" ``
|
||||
. ds R" ''
|
||||
. ds C`
|
||||
. ds C'
|
||||
'br\}
|
||||
.\"
|
||||
.\" Escape single quotes in literal strings from groff's Unicode transform.
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\"
|
||||
.\" If the F register is turned on, we'll generate index entries on stderr for
|
||||
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
|
||||
.\" entries marked with X<> in POD. Of course, you'll have to process the
|
||||
.\" output yourself in some meaningful fashion.
|
||||
.\"
|
||||
.\" Avoid warning from groff about undefined register 'F'.
|
||||
.de IX
|
||||
..
|
||||
.nr rF 0
|
||||
.if \n(.g .if rF .nr rF 1
|
||||
.if (\n(rF:(\n(.g==0)) \{
|
||||
. if \nF \{
|
||||
. de IX
|
||||
. tm Index:\\$1\t\\n%\t"\\$2"
|
||||
..
|
||||
. if !\nF==2 \{
|
||||
. nr % 0
|
||||
. nr F 2
|
||||
. \}
|
||||
. \}
|
||||
.\}
|
||||
.rr rF
|
||||
.\" ========================================================================
|
||||
.\"
|
||||
.IX Title "Test::Tap 1"
|
||||
.TH Test::Tap 1 "January 2016" "Generated by Swim v0.1.41" "\s-1TAP\s0 Test Base for Bash"
|
||||
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
||||
.\" way too many mistakes in technical documents.
|
||||
.if n .ad l
|
||||
.nh
|
||||
.SH "Name"
|
||||
.IX Header "Name"
|
||||
Test::Tap \- \s-1TAP\s0 Test Base for Bash
|
||||
.SH "Synopsis"
|
||||
.IX Header "Synopsis"
|
||||
.Vb 1
|
||||
\& source test/tap.bash
|
||||
\&
|
||||
\& Test::Tap:plan tests 1
|
||||
\&
|
||||
\& pass \*(AqEverything is OK!\*(Aq
|
||||
.Ve
|
||||
.SH "Description"
|
||||
.IX Header "Description"
|
||||
This is a \s-1TAP\s0 testing base class for Bash. It has all the basic \s-1TAP\s0 functions, and works properly from a \s-1TAP\s0 harness, like the \f(CW\*(C`prove\*(C'\fR utility.
|
||||
.PP
|
||||
test-tap-bash is used as the base for test-more-bash, which is what you want if you are writing tests in bash.
|
||||
.PP
|
||||
See: <https://github.com/ingydotnet/test\-more\-bash/>
|
||||
.SH "Functions"
|
||||
.IX Header "Functions"
|
||||
.ie n .IP """Test::Tap:init""" 4
|
||||
.el .IP "\f(CWTest::Tap:init\fR" 4
|
||||
.IX Item "Test::Tap:init"
|
||||
Must be called first for every test file/process.
|
||||
.ie n .IP """Test::Tap::plan""" 4
|
||||
.el .IP "\f(CWTest::Tap::plan\fR" 4
|
||||
.IX Item "Test::Tap::plan"
|
||||
Used to set the plan.
|
||||
.SH "TODO"
|
||||
.IX Header "TODO"
|
||||
.IP "\(bu" 4
|
||||
Finish this doc.
|
||||
.SH "Author"
|
||||
.IX Header "Author"
|
||||
Written by Ingy döt Net <ingy@ingy.net>
|
||||
.SH "Copyright & License"
|
||||
.IX Header "Copyright & License"
|
||||
Copyright 2013\-2016. Ingy döt Net.
|
||||
.PP
|
||||
The \s-1MIT\s0 License (\s-1MIT\s0).
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source test/helper.bash
|
||||
source lib/test/tap.bash
|
||||
|
||||
Test::Tap:init tests 1
|
||||
|
||||
output=$(prove -v test/test/{b,f}ail.t 2>&1)
|
||||
|
||||
test-helper:like \
|
||||
"$output" \
|
||||
'Bailout called. Further testing stopped: Get me outta here' \
|
||||
'Test::Tap:BAIL_OUT works'
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source lib/test/tap.bash
|
||||
|
||||
Test::Tap:init
|
||||
|
||||
Test::Tap:pass one
|
||||
Test::Tap:pass two
|
||||
|
||||
Test::Tap:done_testing
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source test/helper.bash
|
||||
source lib/test/tap.bash
|
||||
|
||||
Test::Tap:init tests 2
|
||||
|
||||
output="$(prove -v test/test/fail.t 2>&1)"
|
||||
|
||||
# echo "# >>>${output//$'\n'/$'\n'# }<<<" >&2
|
||||
|
||||
test-helper:like \
|
||||
"$output" \
|
||||
'not ok 1 - I am a failure' \
|
||||
'Test::Tap:fail works'
|
||||
|
||||
test-helper:like \
|
||||
"$output" \
|
||||
'Failed 1/1 subtests' \
|
||||
'Proper summary'
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source test/helper.bash
|
||||
source lib/test/tap.bash
|
||||
|
||||
Test::Tap:init tests 1
|
||||
|
||||
output="$(prove -v test/test/fail_fast.t 2>&1)"
|
||||
|
||||
# echo ">>>$output<<<" >&2
|
||||
|
||||
test-helper:like \
|
||||
"$output" \
|
||||
'Further testing stopped: Bailing out on status=1' \
|
||||
'Test::Tap:BAIL_OUT works'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
test-helper:like() {
|
||||
local got=$1 regex=$2 label=$3
|
||||
if [[ "$got" =~ "$regex" ]]; then
|
||||
Test::Tap:pass "$label"
|
||||
else
|
||||
Test::Tap:fail "$label"
|
||||
Test::Tap:diag "Got: '$got'"
|
||||
fi
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source lib/test/tap.bash
|
||||
|
||||
Test::Tap:init tests 3
|
||||
|
||||
Test::Tap:pass 'pass 1 - with label'
|
||||
Test::Tap:pass
|
||||
Test::Tap:pass 'pass 3 - 2 has no label'
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source lib/test/tap.bash
|
||||
|
||||
Test::Tap:init
|
||||
Test::Tap:plan tests 3
|
||||
|
||||
for n in 1 2 3; do
|
||||
Test::Tap:pass "Test #$n"
|
||||
done
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source test/helper.bash
|
||||
source lib/test/tap.bash
|
||||
|
||||
Test::Tap:init tests 4
|
||||
|
||||
for s in plan init; do
|
||||
output=$(prove test/test/skip-all-$s.t)
|
||||
|
||||
test-helper:like \
|
||||
"$output" \
|
||||
"skipped: Test for skip_all from $s" \
|
||||
"skip_all from $s: it works"
|
||||
|
||||
test-helper:like \
|
||||
"$output" \
|
||||
'Result: NOTESTS' \
|
||||
"skip_all from $s: No tests run"
|
||||
done
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source lib/test/tap.bash
|
||||
|
||||
Test::Tap:init tests 4
|
||||
|
||||
Test::Tap:pass 'pass with label'
|
||||
Test::Tap:pass
|
||||
Test::Tap:pass 'previous test has no label'
|
||||
msg="$(Test::Tap:fail 'faaaaailll' 2>/dev/null)"
|
||||
if [[ "$msg" =~ not\ ok\ 4\ -\ faaaaailll ]]; then
|
||||
Test::Tap:pass 'fail works'
|
||||
fi
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source lib/test/tap.bash
|
||||
|
||||
Test::Tap:init tests 5
|
||||
|
||||
Test::Tap:pass 'test #1'
|
||||
Test::Tap:pass 'test #2'
|
||||
Test::Tap:pass 'test #3'
|
||||
|
||||
Test::Tap:BAIL_OUT 'Get me outta here'
|
||||
|
||||
Test::Tap:pass 'test #4'
|
||||
Test::Tap:fail 'test #5'
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source lib/test/tap.bash
|
||||
|
||||
Test::Tap:init tests 1
|
||||
|
||||
Test::Tap:fail 'I am a failure'
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source lib/test/tap.bash
|
||||
|
||||
Test::Tap:init tests 5
|
||||
Test::Tap:BAIL_ON_FAIL
|
||||
|
||||
Test::Tap:pass 'test #1'
|
||||
Test::Tap:pass 'test #2'
|
||||
Test::Tap:fail 'test #3'
|
||||
Test::Tap:pass 'test #4'
|
||||
Test::Tap:pass 'test #5'
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source lib/test/tap.bash
|
||||
|
||||
Test::Tap:init skip_all 'Test for skip_all from init'
|
||||
|
||||
Test::Tap:diag "This code should not be run"
|
||||
Test::Tap:fail
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source lib/test/tap.bash
|
||||
|
||||
Test::Tap:init
|
||||
Test::Tap:plan skip_all 'Test for skip_all from plan'
|
||||
|
||||
Test::Tap:diag "This code should not be run"
|
||||
Test::Tap:fail
|
||||
173
build/git-subrepo/ext/test-more-bash/man/man3/test-more.3
Normal file
173
build/git-subrepo/ext/test-more-bash/man/man3/test-more.3
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28)
|
||||
.\"
|
||||
.\" Standard preamble:
|
||||
.\" ========================================================================
|
||||
.de Sp \" Vertical space (when we can't use .PP)
|
||||
.if t .sp .5v
|
||||
.if n .sp
|
||||
..
|
||||
.de Vb \" Begin verbatim text
|
||||
.ft CW
|
||||
.nf
|
||||
.ne \\$1
|
||||
..
|
||||
.de Ve \" End verbatim text
|
||||
.ft R
|
||||
.fi
|
||||
..
|
||||
.\" Set up some character translations and predefined strings. \*(-- will
|
||||
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
|
||||
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
|
||||
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
|
||||
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
|
||||
.\" nothing in troff, for use with C<>.
|
||||
.tr \(*W-
|
||||
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
|
||||
.ie n \{\
|
||||
. ds -- \(*W-
|
||||
. ds PI pi
|
||||
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
|
||||
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
|
||||
. ds L" ""
|
||||
. ds R" ""
|
||||
. ds C` ""
|
||||
. ds C' ""
|
||||
'br\}
|
||||
.el\{\
|
||||
. ds -- \|\(em\|
|
||||
. ds PI \(*p
|
||||
. ds L" ``
|
||||
. ds R" ''
|
||||
. ds C`
|
||||
. ds C'
|
||||
'br\}
|
||||
.\"
|
||||
.\" Escape single quotes in literal strings from groff's Unicode transform.
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\"
|
||||
.\" If the F register is turned on, we'll generate index entries on stderr for
|
||||
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
|
||||
.\" entries marked with X<> in POD. Of course, you'll have to process the
|
||||
.\" output yourself in some meaningful fashion.
|
||||
.\"
|
||||
.\" Avoid warning from groff about undefined register 'F'.
|
||||
.de IX
|
||||
..
|
||||
.nr rF 0
|
||||
.if \n(.g .if rF .nr rF 1
|
||||
.if (\n(rF:(\n(.g==0)) \{
|
||||
. if \nF \{
|
||||
. de IX
|
||||
. tm Index:\\$1\t\\n%\t"\\$2"
|
||||
..
|
||||
. if !\nF==2 \{
|
||||
. nr % 0
|
||||
. nr F 2
|
||||
. \}
|
||||
. \}
|
||||
.\}
|
||||
.rr rF
|
||||
.\" ========================================================================
|
||||
.\"
|
||||
.IX Title "Test::More 1"
|
||||
.TH Test::More 1 "January 2016" "Generated by Swim v0.1.41" "\s-1TAP\s0 Testing for Bash"
|
||||
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
||||
.\" way too many mistakes in technical documents.
|
||||
.if n .ad l
|
||||
.nh
|
||||
.SH "Name"
|
||||
.IX Header "Name"
|
||||
Test::More \- \s-1TAP\s0 Testing for Bash
|
||||
.SH "Synopsis"
|
||||
.IX Header "Synopsis"
|
||||
Write a test file like this. Maybe call it \f(CW\*(C`test/test.t\*(C'\fR:
|
||||
.PP
|
||||
.Vb 1
|
||||
\& #!/usr/bin/env bash
|
||||
\&
|
||||
\& TEST_MORE_PATH="/path/to/test\-more\-bash"
|
||||
\& BASHLIB="\`
|
||||
\& find $TEST_MORE_PATH \-type d |
|
||||
\& grep \-E \*(Aq/(bin|lib)$\*(Aq |
|
||||
\& xargs \-n1 printf "%s:"\`"
|
||||
\& PATH="$BASHLIB$PATH"
|
||||
\&
|
||||
\& source bash+ :std
|
||||
\&
|
||||
\& use Test::More
|
||||
\&
|
||||
\& plan tests 8
|
||||
\&
|
||||
\& some\-command
|
||||
\& ok $? \*(Aqsome\-command is ok\*(Aq
|
||||
\&
|
||||
\& # or:
|
||||
\& ok "\`some\-command\`" \*(Aqsome\-command is ok\*(Aq
|
||||
\&
|
||||
\& pass \*(AqThis will always pass\*(Aq
|
||||
\&
|
||||
\& fail \*(AqThis will always fail\*(Aq
|
||||
\&
|
||||
\& is \`echo foo\` \*(Aqfoo\*(Aq \*(Aqfoo is foo\*(Aq
|
||||
\&
|
||||
\& isnt foo bar "foo isn\*(Aqt bar"
|
||||
\&
|
||||
\& like food foo \*(Aqfood is like foo\*(Aq
|
||||
\&
|
||||
\& unlike team I "There\*(Aqs no \*(AqI\*(Aq in \*(Aqteam\*(Aq"
|
||||
\&
|
||||
\& diag "A message for stderr"
|
||||
\&
|
||||
\& note "A message for stdout"
|
||||
.Ve
|
||||
.PP
|
||||
Run the test with \f(CW\*(C`prove\*(C'\fR like this:
|
||||
.PP
|
||||
.Vb 1
|
||||
\& prove test/test.t
|
||||
.Ve
|
||||
.PP
|
||||
Prove knows it's Bash from the first line (the hashbang), and it just works.
|
||||
.SH "Description"
|
||||
.IX Header "Description"
|
||||
Test::More is the tried and true testing library for Perl. It uses \s-1TAP \s0(the Test Anything Protocol). This is the same thing for Bash. For the most part it should work exactly the same.
|
||||
.SH "Methods"
|
||||
.IX Header "Methods"
|
||||
This is the basic usage:
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`plan tests $count\*(C'\fR
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`ok $status_code "$label"\*(C'\fR
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`pass "$label"\*(C'\fR
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`fail "$label"\*(C'\fR
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`is "$got" "$want" "label"\*(C'\fR
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`isnt "$got" "$unwanted" "$label"\*(C'\fR
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`like "$got" "$regex" "$label"\*(C'\fR
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`unlike "$got" "$regex" "$label"\*(C'\fR
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`diag "$message"\*(C'\fR
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`note "$message"\*(C'\fR
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`done_testing $count\*(C'\fR
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`plan skip_all "$reason"\*(C'\fR
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`BAIL_OUT "$reason"\*(C'\fR
|
||||
.PP
|
||||
More detailed info coming soon.
|
||||
.SH "Author"
|
||||
.IX Header "Author"
|
||||
Ingy döt Net <ingy@bpan.org>
|
||||
.SH "Copyright & License"
|
||||
.IX Header "Copyright & License"
|
||||
Copyright 2013\-2016. Ingy döt Net.
|
||||
.PP
|
||||
The \s-1MIT\s0 License (\s-1MIT\s0)
|
||||
20
build/git-subrepo/ext/test-more-bash/test/fail.t
Normal file
20
build/git-subrepo/ext/test-more-bash/test/fail.t
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source test/setup
|
||||
|
||||
use Test::More
|
||||
|
||||
output=$(prove -v test/test/fail1.t 2>&1) || true
|
||||
|
||||
like "$output" 'not ok 1 - fail with label' \
|
||||
'fail with label'
|
||||
like "$output" 'not ok 2' \
|
||||
'fail with no label'
|
||||
like "$output" 'not ok 3 - is foo bar' \
|
||||
'fail output is correct'
|
||||
like "$output" "# got: 'foo'" \
|
||||
'difference reporting - got'
|
||||
like "$output" "# expected: 'bar'" \
|
||||
'difference reporting - want'
|
||||
|
||||
done_testing 5
|
||||
20
build/git-subrepo/ext/test-more-bash/test/more.t
Normal file
20
build/git-subrepo/ext/test-more-bash/test/more.t
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source test/setup
|
||||
use Test::More
|
||||
|
||||
plan tests 5
|
||||
|
||||
pass 'This test always passes'
|
||||
|
||||
is 'foo' "foo" 'foo is foo'
|
||||
|
||||
ok "`true`" 'true is true'
|
||||
|
||||
ok "`[ 123 -eq $((61+62)) ]`" 'Math works'
|
||||
|
||||
ok "`[[ ! team =~ I ]]`" "There's no I in team"
|
||||
|
||||
# diag "A msg for stderr"
|
||||
|
||||
note "A msg for stdout"
|
||||
9
build/git-subrepo/ext/test-more-bash/test/pass.t
Normal file
9
build/git-subrepo/ext/test-more-bash/test/pass.t
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source test/setup
|
||||
|
||||
use Test::More tests 3
|
||||
|
||||
pass 'pass 1 - with label'
|
||||
pass
|
||||
pass 'pass 3 - 2 has no label'
|
||||
8
build/git-subrepo/ext/test-more-bash/test/setup
Normal file
8
build/git-subrepo/ext/test-more-bash/test/setup
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
BASHLIB="`find $PWD -type d | grep -E '/(bin|lib)$' | xargs -n1 printf "%s:"`"
|
||||
PATH="$BASHLIB:$PATH"
|
||||
|
||||
source bash+ :std
|
||||
11
build/git-subrepo/ext/test-more-bash/test/skip_all.t
Normal file
11
build/git-subrepo/ext/test-more-bash/test/skip_all.t
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source test/setup
|
||||
use Test::More
|
||||
|
||||
output=$(prove -v test/test/skip_all.t 2>&1) || true
|
||||
|
||||
like "$output" 'skipped: Skipping this test to demo skip_all' \
|
||||
'skip_all works'
|
||||
|
||||
done_testing 1
|
||||
12
build/git-subrepo/ext/test-more-bash/test/test/fail1.t
Normal file
12
build/git-subrepo/ext/test-more-bash/test/test/fail1.t
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source test/setup
|
||||
use Test::More
|
||||
|
||||
fail 'fail with label'
|
||||
|
||||
fail
|
||||
|
||||
is foo bar 'is foo bar'
|
||||
|
||||
done_testing 3
|
||||
10
build/git-subrepo/ext/test-more-bash/test/test/skip_all.t
Normal file
10
build/git-subrepo/ext/test-more-bash/test/test/skip_all.t
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source test/setup
|
||||
use Test::More
|
||||
|
||||
plan skip_all 'Skipping this test to demo skip_all'
|
||||
|
||||
fail "Don't run this code"
|
||||
|
||||
done_testing
|
||||
743
build/git-subrepo/man/man1/git-subrepo.1
Normal file
743
build/git-subrepo/man/man1/git-subrepo.1
Normal file
|
|
@ -0,0 +1,743 @@
|
|||
.\" Automatically generated by Pod::Man 4.10 (Pod::Simple 3.35)
|
||||
.\"
|
||||
.\" Standard preamble:
|
||||
.\" ========================================================================
|
||||
.de Sp \" Vertical space (when we can't use .PP)
|
||||
.if t .sp .5v
|
||||
.if n .sp
|
||||
..
|
||||
.de Vb \" Begin verbatim text
|
||||
.ft CW
|
||||
.nf
|
||||
.ne \\$1
|
||||
..
|
||||
.de Ve \" End verbatim text
|
||||
.ft R
|
||||
.fi
|
||||
..
|
||||
.\" Set up some character translations and predefined strings. \*(-- will
|
||||
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
|
||||
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
|
||||
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
|
||||
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
|
||||
.\" nothing in troff, for use with C<>.
|
||||
.tr \(*W-
|
||||
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
|
||||
.ie n \{\
|
||||
. ds -- \(*W-
|
||||
. ds PI pi
|
||||
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
|
||||
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
|
||||
. ds L" ""
|
||||
. ds R" ""
|
||||
. ds C` ""
|
||||
. ds C' ""
|
||||
'br\}
|
||||
.el\{\
|
||||
. ds -- \|\(em\|
|
||||
. ds PI \(*p
|
||||
. ds L" ``
|
||||
. ds R" ''
|
||||
. ds C`
|
||||
. ds C'
|
||||
'br\}
|
||||
.\"
|
||||
.\" Escape single quotes in literal strings from groff's Unicode transform.
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\"
|
||||
.\" If the F register is >0, we'll generate index entries on stderr for
|
||||
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
|
||||
.\" entries marked with X<> in POD. Of course, you'll have to process the
|
||||
.\" output yourself in some meaningful fashion.
|
||||
.\"
|
||||
.\" Avoid warning from groff about undefined register 'F'.
|
||||
.de IX
|
||||
..
|
||||
.nr rF 0
|
||||
.if \n(.g .if rF .nr rF 1
|
||||
.if (\n(rF:(\n(.g==0)) \{\
|
||||
. if \nF \{\
|
||||
. de IX
|
||||
. tm Index:\\$1\t\\n%\t"\\$2"
|
||||
..
|
||||
. if !\nF==2 \{\
|
||||
. nr % 0
|
||||
. nr F 2
|
||||
. \}
|
||||
. \}
|
||||
.\}
|
||||
.rr rF
|
||||
.\" ========================================================================
|
||||
.\"
|
||||
.IX Title "STDIN 1"
|
||||
.TH STDIN 1 "January 2020" "Generated by Swim v0.1.48" "Git Submodule Alternative"
|
||||
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
||||
.\" way too many mistakes in technical documents.
|
||||
.if n .ad l
|
||||
.nh
|
||||
.SH "Name"
|
||||
.IX Header "Name"
|
||||
git-subrepo \- Git Submodule Alternative
|
||||
.SH "Synopsis"
|
||||
.IX Header "Synopsis"
|
||||
.Vb 1
|
||||
\& git subrepo \-h # Help Overview
|
||||
\&
|
||||
\& git subrepo clone <remote\-url> [<subdir>]
|
||||
\& git subrepo init <subdir>
|
||||
\& git subrepo pull <subdir>
|
||||
\& git subrepo push <subdir>
|
||||
\&
|
||||
\& git subrepo fetch <subdir>
|
||||
\& git subrepo branch <subdir>
|
||||
\& git subrepo commit <subdir>
|
||||
\& git subrepo config <subdir>
|
||||
\&
|
||||
\& git subrepo status [<subdir>]
|
||||
\& git subrepo clean <subdir>
|
||||
\&
|
||||
\& git subrepo help [<command> | \-\-all]
|
||||
\& git subrepo version
|
||||
\& git subrepo upgrade
|
||||
.Ve
|
||||
.SH "Description"
|
||||
.IX Header "Description"
|
||||
This git command \*(L"clones\*(R" an external git repo into a subdirectory of your
|
||||
repo. Later on, upstream changes can be pulled in, and local changes can be
|
||||
pushed back. Simple.
|
||||
.SH "Benefits"
|
||||
.IX Header "Benefits"
|
||||
This command is an improvement from \f(CW\*(C`git\-submodule\*(C'\fR and \f(CW\*(C`git\-subtree\*(C'\fR; two
|
||||
other git commands with similar goals, but various problems.
|
||||
.PP
|
||||
It assumes there are 3 main roles of people interacting with a repo, and
|
||||
attempts to serve them all well:
|
||||
.IP "\(bu" 4
|
||||
\&\fBowner\fR \- The person who authors/owns/maintains a repo.
|
||||
.IP "\(bu" 4
|
||||
\&\fBusers\fR \- People who are just using/installing the repo.
|
||||
.IP "\(bu" 4
|
||||
\&\fBcollaborators\fR \- People who commit code to the repo and subrepos.
|
||||
.PP
|
||||
The \f(CW\*(C`git\-subrepo\*(C'\fR command benefits these roles in the following ways:
|
||||
.IP "\(bu" 4
|
||||
Simple and intuitive commandline usage (with tab completion).
|
||||
.IP "\(bu" 4
|
||||
Users get your repo and all your subrepos just by cloning your repo.
|
||||
.IP "\(bu" 4
|
||||
Users do not need to install \f(CW\*(C`git\-subrepo\*(C'\fR, ever.
|
||||
.IP "\(bu" 4
|
||||
Collaborators do not need to install unless they want to push/pull.
|
||||
.IP "\(bu" 4
|
||||
Collaborators know when a subdir is a subrepo (it has a \f(CW\*(C`.gitrepo\*(C'\fR file).
|
||||
.IP "\(bu" 4
|
||||
The \f(CW\*(C`.gitrepo\*(C'\fR file never gets pushed back to the subrepo upstream.
|
||||
.IP "\(bu" 4
|
||||
Well named branches and remotes are generated for manual operations.
|
||||
.IP "\(bu" 4
|
||||
Owners do not deal with the complications of keeping submodules in sync.
|
||||
.IP "\(bu" 4
|
||||
Subrepo repositories can contain subrepos themselves.
|
||||
.IP "\(bu" 4
|
||||
Branching with subrepos JustWorks™.
|
||||
.IP "\(bu" 4
|
||||
Different branches can have different subrepos in different states, etc.
|
||||
.IP "\(bu" 4
|
||||
Moving/renaming/deleting a subrepo subdir JustWorks™.
|
||||
.IP "\(bu" 4
|
||||
You can \f(CW\*(C`init\*(C'\fR an existing subdirectory into a subrepo.
|
||||
.IP "\(bu" 4
|
||||
Your git history is kept squeaky clean.
|
||||
.IP "\(bu" 4
|
||||
Upstream history (clone/pull) is condensed into a single commit.
|
||||
.IP "\(bu" 4
|
||||
Pulls can use a \f(CW\*(C`merge\*(C'\fR, \f(CW\*(C`rebase\*(C'\fR or \f(CW\*(C`force\*(C'\fR strategies.
|
||||
.IP "\(bu" 4
|
||||
You can see the subrepo history with \f(CW\*(C`git log subrepo/<subdir>/fetch\*(C'\fR.
|
||||
.IP "\(bu" 4
|
||||
Commits pushed back upstream are \fBnot\fR condensed (by default).
|
||||
.IP "\(bu" 4
|
||||
Trivial to try any subrepo operations and then reset back.
|
||||
.IP "\(bu" 4
|
||||
No configuration required.
|
||||
.IP "\(bu" 4
|
||||
Does not introduce history that messes up other git commands.
|
||||
.IP "\(bu" 4
|
||||
Fixes known rebase failures with \f(CW\*(C`git\-subtree\*(C'\fR.
|
||||
.SH "Installation"
|
||||
.IX Header "Installation"
|
||||
The best short answer is:
|
||||
.PP
|
||||
.Vb 2
|
||||
\& git clone https://github.com/ingydotnet/git\-subrepo /path/to/git\-subrepo
|
||||
\& echo \*(Aqsource /path/to/git\-subrepo/.rc\*(Aq >> ~/.bashrc
|
||||
.Ve
|
||||
.PP
|
||||
The complete \*(L"Installation Instructions\*(R" can be found below.
|
||||
.PP
|
||||
Note: git-subrepo needs a git version (> 2.7) that supports worktree:s.
|
||||
.SH "Commands"
|
||||
.IX Header "Commands"
|
||||
All the \fBsubrepo\fR commands use names of actual Git commands and try to do
|
||||
operations that are similar to their Git counterparts. They also attempt to
|
||||
give similar output in an attempt to make the subrepo usage intuitive to
|
||||
experienced Git users.
|
||||
.PP
|
||||
Please note that the commands are \fInot\fR exact equivalents, and do not take
|
||||
all the same arguments. Keep reading…
|
||||
.ie n .IP """git subrepo clone <repository> [<subdir>] [\-b <branch>] [\-f] [\-m <msg>] [\-e] [\-\-method <merge|rebase>]""" 4
|
||||
.el .IP "\f(CWgit subrepo clone <repository> [<subdir>] [\-b <branch>] [\-f] [\-m <msg>] [\-e] [\-\-method <merge|rebase>]\fR" 4
|
||||
.IX Item "git subrepo clone <repository> [<subdir>] [-b <branch>] [-f] [-m <msg>] [-e] [--method <merge|rebase>]"
|
||||
Add a repository as a subrepo in a subdir of your repository.
|
||||
.Sp
|
||||
This is similar in feel to \f(CW\*(C`git clone\*(C'\fR. You just specify the remote repo url,
|
||||
and optionally a sub-directory and/or branch name. The repo will be fetched
|
||||
and merged into the subdir.
|
||||
.Sp
|
||||
The subrepo history is \fIsquashed\fR into a single commit that contains the
|
||||
reference information. This information is also stored in a special file
|
||||
called \f(CW\*(C`<subdir>/.gitrepo\*(C'\fR. The presence of this file indicates that the
|
||||
directory is a subrepo.
|
||||
.Sp
|
||||
All subsequent commands refer to the subrepo by the name of the
|
||||
\&\fIsubdir\fR. From the subdir, all the current information about the subrepo
|
||||
can be obtained.
|
||||
.Sp
|
||||
The \f(CW\*(C`\-\-force\*(C'\fR option will \*(L"reclone\*(R" (completely replace) an existing subdir.
|
||||
.Sp
|
||||
The \f(CW\*(C`\-\-method\*(C'\fR option will decide how the join process between branches are
|
||||
performed. The default option is merge.
|
||||
.Sp
|
||||
The \f(CW\*(C`clone\*(C'\fR command accepts the \f(CW\*(C`\-\-branch=\*(C'\fR \f(CW\*(C`\-\-edit\*(C'\fR, \f(CW\*(C`\-\-force\*(C'\fR and \f(CW\*(C`\-\-
|
||||
message=\*(C'\fR options.
|
||||
.ie n .IP """git subrepo init <subdir> [\-r <remote>] [\-b <branch>] [\-\-method <merge|rebase>]""" 4
|
||||
.el .IP "\f(CWgit subrepo init <subdir> [\-r <remote>] [\-b <branch>] [\-\-method <merge|rebase>]\fR" 4
|
||||
.IX Item "git subrepo init <subdir> [-r <remote>] [-b <branch>] [--method <merge|rebase>]"
|
||||
Turn an existing subdirectory into a subrepo.
|
||||
.Sp
|
||||
If you want to expose a subdirectory of your project as a published subrepo,
|
||||
this command will do that. It will split out the content of a normal
|
||||
subdirectory into a branch and start tracking it as a subrepo. Afterwards your
|
||||
original repo will look exactly the same except that there will be a \f(CW\*(C`<subdir>/.gitrepo\*(C'\fR file.
|
||||
.Sp
|
||||
If you specify the \f(CW\*(C`\-\-remote\*(C'\fR (and optionally the \f(CW\*(C`\-\-branch\*(C'\fR) option, the
|
||||
values will be added to the \f(CW\*(C`<subdir>/.gitrepo\*(C'\fR file. The \f(CW\*(C`\-\-remote\*(C'\fR
|
||||
option is the upstream \s-1URL,\s0 and the \f(CW\*(C`\-\-branch\*(C'\fR option is the upstream branch
|
||||
to push to. These values will be needed to do a \f(CW\*(C`git subrepo push\*(C'\fR command,
|
||||
but they can be provided later on the \f(CW\*(C`push\*(C'\fR command (and saved to \f(CW\*(C`<subdir>/.gitrepo\*(C'\fR if you also specify the \f(CW\*(C`\-\-update\*(C'\fR option).
|
||||
.Sp
|
||||
Note: You will need to create the empty upstream repo and push to it on your
|
||||
own, using \f(CW\*(C`git subrepo push <subdir>\*(C'\fR.
|
||||
.Sp
|
||||
The \f(CW\*(C`\-\-method\*(C'\fR option will decide how the join process between branches are
|
||||
performed. The default option is merge.
|
||||
.Sp
|
||||
The \f(CW\*(C`init\*(C'\fR command accepts the \f(CW\*(C`\-\-branch=\*(C'\fR and \f(CW\*(C`\-\-remote=\*(C'\fR options.
|
||||
.ie n .IP """git subrepo pull <subdir>|\-\-all [\-M|\-R|\-f] [\-m <msg>] [\-e] [\-b <branch>] [\-r <remote>] [\-u]""" 4
|
||||
.el .IP "\f(CWgit subrepo pull <subdir>|\-\-all [\-M|\-R|\-f] [\-m <msg>] [\-e] [\-b <branch>] [\-r <remote>] [\-u]\fR" 4
|
||||
.IX Item "git subrepo pull <subdir>|--all [-M|-R|-f] [-m <msg>] [-e] [-b <branch>] [-r <remote>] [-u]"
|
||||
Update the subrepo subdir with the latest upstream changes.
|
||||
.Sp
|
||||
The \f(CW\*(C`pull\*(C'\fR command fetches the latest content from the remote branch pointed
|
||||
to by the subrepo's \f(CW\*(C`.gitrepo\*(C'\fR file, and then tries to merge the changes into
|
||||
the corresponding subdir. It does this by making a branch of the local commits
|
||||
to the subdir and then merging or rebasing (see below) it with the fetched
|
||||
upstream content. After the merge, the content of the new branch replaces your
|
||||
subdir, the \f(CW\*(C`.gitrepo\*(C'\fR file is updated and a single 'pull' commit is added to
|
||||
your mainline history.
|
||||
.Sp
|
||||
The \f(CW\*(C`pull\*(C'\fR command will attempt to do the following commands in one go:
|
||||
.Sp
|
||||
.Vb 6
|
||||
\& git subrepo fetch <subdir>
|
||||
\& git subrepo branch <subdir>
|
||||
\& git merge/rebase subrepo/<subdir>/fetch subrepo/<subdir>
|
||||
\& git subrepo commit <subdir>
|
||||
\& # Only needed for a consequential push:
|
||||
\& git update\-ref refs/subrepo/<subdir>/pull subrepo/<subdir>
|
||||
.Ve
|
||||
.Sp
|
||||
In other words, you could do all the above commands yourself, for the same
|
||||
effect. If any of the commands fail, subrepo will stop and tell you to finish
|
||||
this by hand. Generally a failure would be in the merge or rebase part, where
|
||||
conflicts can happen. Since Git has lots of ways to resolve conflicts to your
|
||||
personal tastes, the subrepo command defers to letting you do this by hand.
|
||||
.Sp
|
||||
When pulling new data, the method selected in clone/init is used. This has no
|
||||
effect on the final result of the pull, since it becomes a single commit. But
|
||||
it does affect the resulting \f(CW\*(C`subrepo/<subdir>\*(C'\fR branch, which is often
|
||||
used for a subrepo \f(CW\*(C`push\*(C'\fR command. See 'push' below for more information. If
|
||||
you want to change the method you can use the \f(CW\*(C`config\*(C'\fR command for this.
|
||||
.Sp
|
||||
When you pull you can assume a fast-forward strategy (default) or you can
|
||||
specify a \f(CW\*(C`\-\-rebase\*(C'\fR, \f(CW\*(C`\-\-merge\*(C'\fR or \f(CW\*(C`\-\-force\*(C'\fR strategy. The latter is the
|
||||
same as a \f(CW\*(C`clone \-\-force\*(C'\fR operation, using the current remote and branch.
|
||||
.Sp
|
||||
Like the \f(CW\*(C`clone\*(C'\fR command, \f(CW\*(C`pull\*(C'\fR will squash all the changes (since the last
|
||||
pull or clone) into one commit. This keeps your mainline history nice and
|
||||
clean. You can easily see the subrepo's history with the \f(CW\*(C`git log\*(C'\fR command:
|
||||
.Sp
|
||||
.Vb 1
|
||||
\& git log refs/subrepo/<subdir>/fetch
|
||||
.Ve
|
||||
.Sp
|
||||
The set of commands used above are described in detail below.
|
||||
.Sp
|
||||
The \f(CW\*(C`pull\*(C'\fR command accepts the \f(CW\*(C`\-\-all\*(C'\fR, \f(CW\*(C`\-\-branch=\*(C'\fR, \f(CW\*(C`\-\-edit\*(C'\fR, \f(CW\*(C`\-\-force\*(C'\fR,
|
||||
\&\f(CW\*(C`\-\-message=\*(C'\fR, \f(CW\*(C`\-\-remote=\*(C'\fR and \f(CW\*(C`\-\-update\*(C'\fR options.
|
||||
.ie n .IP """git subrepo push <subdir>|\-\-all [<branch>] [\-r <remote>] [\-b <branch>] [\-M|\-R] [\-u] [\-f] [\-s] [\-N]""" 4
|
||||
.el .IP "\f(CWgit subrepo push <subdir>|\-\-all [<branch>] [\-r <remote>] [\-b <branch>] [\-M|\-R] [\-u] [\-f] [\-s] [\-N]\fR" 4
|
||||
.IX Item "git subrepo push <subdir>|--all [<branch>] [-r <remote>] [-b <branch>] [-M|-R] [-u] [-f] [-s] [-N]"
|
||||
Push a properly merged subrepo branch back upstream.
|
||||
.Sp
|
||||
This command takes the subrepo branch from a successful pull command and
|
||||
pushes the history back to its designated remote and branch. You can also use
|
||||
the \f(CW\*(C`branch\*(C'\fR command and merge things yourself before pushing if you want to
|
||||
(although that is probably a rare use case).
|
||||
.Sp
|
||||
The \f(CW\*(C`push\*(C'\fR command requires a branch that has been properly merged/rebased
|
||||
with the upstream \s-1HEAD\s0 (unless the upstream \s-1HEAD\s0 is empty, which is common
|
||||
when doing a first \f(CW\*(C`push\*(C'\fR after an \f(CW\*(C`init\*(C'\fR). That means the upstream \s-1HEAD\s0 is
|
||||
one of the commits in the branch.
|
||||
.Sp
|
||||
By default the branch ref \f(CW\*(C`refs/subrepo/<subdir>/pull\*(C'\fR will be pushed,
|
||||
but you can specify a (properly merged) branch to push.
|
||||
.Sp
|
||||
After that, the \f(CW\*(C`push\*(C'\fR command just checks that the branch contains the
|
||||
upstream \s-1HEAD\s0 and then pushes it upstream.
|
||||
.Sp
|
||||
The \f(CW\*(C`\-\-force\*(C'\fR option will do a force push. Force pushes are typically
|
||||
discouraged. Only use this option if you fully understand it. (The \f(CW\*(C`\-\-force\*(C'\fR
|
||||
option will \s-1NOT\s0 check for a proper merge. \s-1ANY\s0 branch will be force pushed!)
|
||||
.Sp
|
||||
The \f(CW\*(C`push\*(C'\fR command accepts the \f(CW\*(C`\-\-all\*(C'\fR, \f(CW\*(C`\-\-branch=\*(C'\fR, \f(CW\*(C`\-\-dry\-run\*(C'\fR, \f(CW\*(C`\-\-
|
||||
force\*(C'\fR, \f(CW\*(C`\-\-merge\*(C'\fR, \f(CW\*(C`\-\-rebase\*(C'\fR, \f(CW\*(C`\-\-remote=\*(C'\fR, \f(CW\*(C`\-\-squash\*(C'\fR and \f(CW\*(C`\-\-
|
||||
update\*(C'\fR options.
|
||||
.ie n .IP """git subrepo fetch <subdir>|\-\-all [\-r <remote>] [\-b <branch>]""" 4
|
||||
.el .IP "\f(CWgit subrepo fetch <subdir>|\-\-all [\-r <remote>] [\-b <branch>]\fR" 4
|
||||
.IX Item "git subrepo fetch <subdir>|--all [-r <remote>] [-b <branch>]"
|
||||
Fetch the remote/upstream content for a subrepo.
|
||||
.Sp
|
||||
It will create a Git reference called \f(CW\*(C`subrepo/<subdir>/fetch\*(C'\fR that
|
||||
points at the same commit as \f(CW\*(C`FETCH_HEAD\*(C'\fR. It will also create a remote
|
||||
called \f(CW\*(C`subrepo/<subdir>\*(C'\fR. These are temporary and you can easily remove
|
||||
them with the subrepo \f(CW\*(C`clean\*(C'\fR command.
|
||||
.Sp
|
||||
The \f(CW\*(C`fetch\*(C'\fR command accepts the \f(CW\*(C`\-\-all\*(C'\fR, \f(CW\*(C`\-\-branch=\*(C'\fR and \f(CW\*(C`\-\-
|
||||
remote=\*(C'\fR options.
|
||||
.ie n .IP """git subrepo branch <subdir>|\-\-all [\-f] [\-F]""" 4
|
||||
.el .IP "\f(CWgit subrepo branch <subdir>|\-\-all [\-f] [\-F]\fR" 4
|
||||
.IX Item "git subrepo branch <subdir>|--all [-f] [-F]"
|
||||
Create a branch with local subrepo commits.
|
||||
.Sp
|
||||
Scan the history of the mainline for all the commits that affect the \f(CW\*(C`subdir\*(C'\fR
|
||||
and create a new branch from them called \f(CW\*(C`subrepo/<subdir>\*(C'\fR.
|
||||
.Sp
|
||||
This is useful for doing \f(CW\*(C`pull\*(C'\fR and \f(CW\*(C`push\*(C'\fR commands by hand.
|
||||
.Sp
|
||||
Use the \f(CW\*(C`\-\-force\*(C'\fR option to write over an existing \f(CW\*(C`subrepo/<subdir>\*(C'\fR branch.
|
||||
.Sp
|
||||
The \f(CW\*(C`branch\*(C'\fR command accepts the \f(CW\*(C`\-\-all\*(C'\fR, \f(CW\*(C`\-\-fetch\*(C'\fR and \f(CW\*(C`\-\-force\*(C'\fR options.
|
||||
.ie n .IP """git subrepo commit <subdir> [<subrepo\-ref>] [\-m <msg>] [\-e] [\-f] [\-F]""" 4
|
||||
.el .IP "\f(CWgit subrepo commit <subdir> [<subrepo\-ref>] [\-m <msg>] [\-e] [\-f] [\-F]\fR" 4
|
||||
.IX Item "git subrepo commit <subdir> [<subrepo-ref>] [-m <msg>] [-e] [-f] [-F]"
|
||||
Add subrepo branch to current history as a single commit.
|
||||
.Sp
|
||||
This command is generally used after a hand-merge. You have done a \f(CW\*(C`subrepo
|
||||
branch\*(C'\fR and merged (rebased) it with the upstream. This command takes the \s-1HEAD\s0
|
||||
of that branch, puts its content into the subrepo subdir and adds a new commit
|
||||
for it to the top of your mainline history.
|
||||
.Sp
|
||||
This command requires that the upstream \s-1HEAD\s0 be in the \f(CW\*(C`subrepo/<subdir>\*(C'\fR
|
||||
branch history. That way the same branch can push upstream. Use the \f(CW\*(C`\-\-force\*(C'\fR
|
||||
option to commit anyway.
|
||||
.Sp
|
||||
The \f(CW\*(C`commit\*(C'\fR command accepts the \f(CW\*(C`\-\-edit\*(C'\fR, \f(CW\*(C`\-\-fetch\*(C'\fR, \f(CW\*(C`\-\-force\*(C'\fR and \f(CW\*(C`\-\-
|
||||
message=\*(C'\fR options.
|
||||
.ie n .IP """git subrepo status [<subdir>|\-\-all|\-\-ALL] [\-F] [\-q|\-v]""" 4
|
||||
.el .IP "\f(CWgit subrepo status [<subdir>|\-\-all|\-\-ALL] [\-F] [\-q|\-v]\fR" 4
|
||||
.IX Item "git subrepo status [<subdir>|--all|--ALL] [-F] [-q|-v]"
|
||||
Get the status of a subrepo. Uses the \f(CW\*(C`\-\-all\*(C'\fR option by default. If the \f(CW\*(C`\-\-
|
||||
quiet\*(C'\fR flag is used, just print the subrepo names, one per line.
|
||||
.Sp
|
||||
The \f(CW\*(C`\-\-verbose\*(C'\fR option will show all the recent local and upstream commits.
|
||||
.Sp
|
||||
Use \f(CW\*(C`\-\-ALL\*(C'\fR to show the subrepos of the subrepos (ie the
|
||||
\&\*(L"subsubrepos\*(R"), if any.
|
||||
.Sp
|
||||
The \f(CW\*(C`status\*(C'\fR command accepts the \f(CW\*(C`\-\-all\*(C'\fR, \f(CW\*(C`\-\-ALL\*(C'\fR, \f(CW\*(C`\-\-fetch\*(C'\fR, \f(CW\*(C`\-\-quiet\*(C'\fR
|
||||
and \f(CW\*(C`\-\-verbose\*(C'\fR options.
|
||||
.ie n .IP """git subrepo clean <subdir>|\-\-all|\-\-ALL [\-f]""" 4
|
||||
.el .IP "\f(CWgit subrepo clean <subdir>|\-\-all|\-\-ALL [\-f]\fR" 4
|
||||
.IX Item "git subrepo clean <subdir>|--all|--ALL [-f]"
|
||||
Remove artifacts created by \f(CW\*(C`fetch\*(C'\fR and \f(CW\*(C`branch\*(C'\fR commands.
|
||||
.Sp
|
||||
The \f(CW\*(C`fetch\*(C'\fR and \f(CW\*(C`branch\*(C'\fR operations (and other commands that call them)
|
||||
create temporary things like refs, branches and remotes. This command removes
|
||||
all those things.
|
||||
.Sp
|
||||
Use \f(CW\*(C`\-\-force\*(C'\fR to remove refs. Refs are not removed by default because they
|
||||
are sometimes needed between commands.
|
||||
.Sp
|
||||
Use \f(CW\*(C`\-\-all\*(C'\fR to clean up after all the current subrepos. Sometimes you might
|
||||
change to a branch where a subrepo doesn't exist, and then \f(CW\*(C`\-\-all\*(C'\fR won't find
|
||||
it. Use \f(CW\*(C`\-\-ALL\*(C'\fR to remove any artifacts that were ever created by subrepo.
|
||||
.Sp
|
||||
To remove \s-1ALL\s0 subrepo artifacts:
|
||||
.Sp
|
||||
.Vb 1
|
||||
\& git subrepo clean \-\-ALL \-\-force
|
||||
.Ve
|
||||
.Sp
|
||||
The \f(CW\*(C`clean\*(C'\fR command accepts the \f(CW\*(C`\-\-all\*(C'\fR, \f(CW\*(C`\-\-ALL\*(C'\fR, and \f(CW\*(C`\-\-force\*(C'\fR options.
|
||||
.ie n .IP """git subrepo config <subdir> <option> [<value>] [\-f]""" 4
|
||||
.el .IP "\f(CWgit subrepo config <subdir> <option> [<value>] [\-f]\fR" 4
|
||||
.IX Item "git subrepo config <subdir> <option> [<value>] [-f]"
|
||||
Read or update configuration values in the subdir/.gitrepo file.
|
||||
.Sp
|
||||
Because most of the values stored in the .gitrepo file are generated you
|
||||
will need to use \f(CW\*(C`\-\-force\*(C'\fR if you want to change anything else then the
|
||||
\&\f(CW\*(C`method\*(C'\fR option.
|
||||
.Sp
|
||||
Example to update the \f(CW\*(C`method\*(C'\fR option for a subrepo:
|
||||
.Sp
|
||||
.Vb 1
|
||||
\& git subrepo config foo method rebase
|
||||
.Ve
|
||||
.ie n .IP """git subrepo help [<command>|\-\-all]""" 4
|
||||
.el .IP "\f(CWgit subrepo help [<command>|\-\-all]\fR" 4
|
||||
.IX Item "git subrepo help [<command>|--all]"
|
||||
Same as \f(CW\*(C`git help subrepo\*(C'\fR. Will launch the manpage. For the shorter usage,
|
||||
use \f(CW\*(C`git subrepo \-h\*(C'\fR.
|
||||
.Sp
|
||||
Use \f(CW\*(C`git subrepo help <command>\*(C'\fR to get help for a specific command. Use
|
||||
\&\f(CW\*(C`\-\-all\*(C'\fR to get a summary of all commands.
|
||||
.Sp
|
||||
The \f(CW\*(C`help\*(C'\fR command accepts the \f(CW\*(C`\-\-all\*(C'\fR option.
|
||||
.ie n .IP """git subrepo version [\-q|\-v]""" 4
|
||||
.el .IP "\f(CWgit subrepo version [\-q|\-v]\fR" 4
|
||||
.IX Item "git subrepo version [-q|-v]"
|
||||
This command will display version information about git-subrepo and its
|
||||
environment. For just the version number, use \f(CW\*(C`git subrepo \-\-version\*(C'\fR. Use
|
||||
\&\f(CW\*(C`\-\-verbose\*(C'\fR for more version info, and \f(CW\*(C`\-\-quiet\*(C'\fR for less.
|
||||
.Sp
|
||||
The \f(CW\*(C`version\*(C'\fR command accepts the \f(CW\*(C`\-\-quiet\*(C'\fR and \f(CW\*(C`\-\-verbose\*(C'\fR options.
|
||||
.ie n .IP """git subrepo upgrade""" 4
|
||||
.el .IP "\f(CWgit subrepo upgrade\fR" 4
|
||||
.IX Item "git subrepo upgrade"
|
||||
Upgrade the \f(CW\*(C`git\-subrepo\*(C'\fR software itself. This simply does a \f(CW\*(C`git pull\*(C'\fR
|
||||
on the git repository that the code is running from. It only works if you
|
||||
are on the \f(CW\*(C`master\*(C'\fR branch. It won't work if you installed \f(CW\*(C`git\-subrepo\*(C'\fR
|
||||
using \f(CW\*(C`make install\*(C'\fR; in that case you'll need to \f(CW\*(C`make install\*(C'\fR from the
|
||||
latest code.
|
||||
.SH "Command Options"
|
||||
.IX Header "Command Options"
|
||||
.ie n .IP """\-h""" 4
|
||||
.el .IP "\f(CW\-h\fR" 4
|
||||
.IX Item "-h"
|
||||
Show a brief view of the commands and options.
|
||||
.ie n .IP """\-\-help""" 4
|
||||
.el .IP "\f(CW\-\-help\fR" 4
|
||||
.IX Item "--help"
|
||||
Gives an overview of the help options available for the subrepo command.
|
||||
.ie n .IP """\-\-version""" 4
|
||||
.el .IP "\f(CW\-\-version\fR" 4
|
||||
.IX Item "--version"
|
||||
Print the git-subrepo version. Just the version number. Try the \f(CW\*(C`version\*(C'\fR
|
||||
command for more version info.
|
||||
.ie n .IP """\-\-all"" (""\-a"")" 4
|
||||
.el .IP "\f(CW\-\-all\fR (\f(CW\-a\fR)" 4
|
||||
.IX Item "--all (-a)"
|
||||
If you have multiple subrepos, issue the command to all of them (if
|
||||
applicable).
|
||||
.ie n .IP """\-\-ALL"" (""\-A"")" 4
|
||||
.el .IP "\f(CW\-\-ALL\fR (\f(CW\-A\fR)" 4
|
||||
.IX Item "--ALL (-A)"
|
||||
If you have subrepos that also have subrepos themselves, issue the command to
|
||||
\&\s-1ALL\s0 of them. Note that the \f(CW\*(C`\-\-ALL\*(C'\fR option only works for a subset of the
|
||||
commands that \f(CW\*(C`\-\-all\*(C'\fR works for.
|
||||
.ie n .IP """\-\-branch=<branch\-name>"" (""\-b <branch\-name>"")" 4
|
||||
.el .IP "\f(CW\-\-branch=<branch\-name>\fR (\f(CW\-b <branch\-name>\fR)" 4
|
||||
.IX Item "--branch=<branch-name> (-b <branch-name>)"
|
||||
Use a different upstream branch-name than the remote \s-1HEAD\s0 or the one saved in
|
||||
\&\f(CW\*(C`.gitrepo\*(C'\fR locally.
|
||||
.ie n .IP """\-\-dry\-run"" (""\-N"")" 4
|
||||
.el .IP "\f(CW\-\-dry\-run\fR (\f(CW\-N\fR)" 4
|
||||
.IX Item "--dry-run (-N)"
|
||||
For the push command, do everything up until the push and then print out the
|
||||
actual \f(CW\*(C`git push\*(C'\fR command needed to finish the operation.
|
||||
.ie n .IP """\-\-edit"" (""\-e"")" 4
|
||||
.el .IP "\f(CW\-\-edit\fR (\f(CW\-e\fR)" 4
|
||||
.IX Item "--edit (-e)"
|
||||
Edit the commit message before committing.
|
||||
.ie n .IP """\-\-fetch"" (""\-F"")" 4
|
||||
.el .IP "\f(CW\-\-fetch\fR (\f(CW\-F\fR)" 4
|
||||
.IX Item "--fetch (-F)"
|
||||
Use this option to fetch the upstream commits, before running the command.
|
||||
.ie n .IP """\-\-force"" (""\-f"")" 4
|
||||
.el .IP "\f(CW\-\-force\fR (\f(CW\-f\fR)" 4
|
||||
.IX Item "--force (-f)"
|
||||
Use this option to force certain commands that fail in the general case.
|
||||
.Sp
|
||||
\&\s-1NOTE:\s0 The \f(CW\*(C`\-\-force\*(C'\fR option means different things for different commands.
|
||||
Read the command specific doc for the exact meaning.
|
||||
.ie n .IP """\-\-merge"" (""\-M"")" 4
|
||||
.el .IP "\f(CW\-\-merge\fR (\f(CW\-M\fR)" 4
|
||||
.IX Item "--merge (-M)"
|
||||
Use a \f(CW\*(C`merge\*(C'\fR strategy to include upstream subrepo commits on a pull (or
|
||||
setup for push).
|
||||
.ie n .IP """\-\-message=<message>"" (""\-m <message>"")" 4
|
||||
.el .IP "\f(CW\-\-message=<message>\fR (\f(CW\-m <message>\fR)" 4
|
||||
.IX Item "--message=<message> (-m <message>)"
|
||||
Specify your own commit message on the command line.
|
||||
.ie n .IP """\-\-rebase"" (""\-R"")" 4
|
||||
.el .IP "\f(CW\-\-rebase\fR (\f(CW\-R\fR)" 4
|
||||
.IX Item "--rebase (-R)"
|
||||
Use a \f(CW\*(C`rebase\*(C'\fR strategy to include upstream subrepo commits on a pull (or
|
||||
setup for push).
|
||||
.ie n .IP """\-\-remote=<remote\-url>"" (""\-r <remote\-url>"")" 4
|
||||
.el .IP "\f(CW\-\-remote=<remote\-url>\fR (\f(CW\-r <remote\-url>\fR)" 4
|
||||
.IX Item "--remote=<remote-url> (-r <remote-url>)"
|
||||
Use a different remote-url than the one saved in \f(CW\*(C`.gitrepo\*(C'\fR locally.
|
||||
.ie n .IP """\-\-squash"" (""\-s"")" 4
|
||||
.el .IP "\f(CW\-\-squash\fR (\f(CW\-s\fR)" 4
|
||||
.IX Item "--squash (-s)"
|
||||
Squash all commits on a push into one new commit.
|
||||
.ie n .IP """\-\-update"" (""\-u"")" 4
|
||||
.el .IP "\f(CW\-\-update\fR (\f(CW\-u\fR)" 4
|
||||
.IX Item "--update (-u)"
|
||||
If \f(CW\*(C`\-\-branch\*(C'\fR or \f(CW\*(C`\-\-remote\*(C'\fR are used, and the command updates the
|
||||
\&\f(CW\*(C`.gitrepo\*(C'\fR file, include these values to the update.
|
||||
.SH "Output Options"
|
||||
.IX Header "Output Options"
|
||||
.ie n .IP """\-\-quiet"" (""\-q"")" 4
|
||||
.el .IP "\f(CW\-\-quiet\fR (\f(CW\-q\fR)" 4
|
||||
.IX Item "--quiet (-q)"
|
||||
Print as little info as possible. Applicable to most commands.
|
||||
.ie n .IP """\-\-verbose"" (""\-v"")" 4
|
||||
.el .IP "\f(CW\-\-verbose\fR (\f(CW\-v\fR)" 4
|
||||
.IX Item "--verbose (-v)"
|
||||
Print more information about the command execution and results. Applicable to
|
||||
most commands.
|
||||
.ie n .IP """\-\-debug"" (""\-d"")" 4
|
||||
.el .IP "\f(CW\-\-debug\fR (\f(CW\-d\fR)" 4
|
||||
.IX Item "--debug (-d)"
|
||||
Show the actual git (and other) commands being executed under the hood.
|
||||
Applicable to most commands.
|
||||
.ie n .IP """\-\-DEBUG"" (""\-x"")" 4
|
||||
.el .IP "\f(CW\-\-DEBUG\fR (\f(CW\-x\fR)" 4
|
||||
.IX Item "--DEBUG (-x)"
|
||||
Use the Bash \f(CW\*(C`set \-x\*(C'\fR option which prints every command before it is
|
||||
run. \s-1VERY\s0 noisy, but extremely useful in deep debugging. Applicable to
|
||||
all commands.
|
||||
.SH "Environment Variables"
|
||||
.IX Header "Environment Variables"
|
||||
The \f(CW\*(C`git\-subrepo\*(C'\fR command exports and honors some environment variables:
|
||||
.ie n .IP """GIT_SUBREPO_ROOT""" 4
|
||||
.el .IP "\f(CWGIT_SUBREPO_ROOT\fR" 4
|
||||
.IX Item "GIT_SUBREPO_ROOT"
|
||||
This is set by the \f(CW\*(C`.rc\*(C'\fR file, if you use that method to install / enable \f(CW\*(C`git\-
|
||||
subrepo\*(C'\fR. It contains the path of the \f(CW\*(C`git\-subrepo\*(C'\fR repository.
|
||||
.ie n .IP """GIT_SUBREPO_RUNNING""" 4
|
||||
.el .IP "\f(CWGIT_SUBREPO_RUNNING\fR" 4
|
||||
.IX Item "GIT_SUBREPO_RUNNING"
|
||||
This variable is exported when \f(CW\*(C`git\-subrepo\*(C'\fR is running. It is set to the pid
|
||||
of the \f(CW\*(C`git\-subrepo\*(C'\fR process that is running. Other processes, like git hooks
|
||||
for instance, can use this information to adjust accordingly.
|
||||
.ie n .IP """GIT_SUBREPO_COMMAND""" 4
|
||||
.el .IP "\f(CWGIT_SUBREPO_COMMAND\fR" 4
|
||||
.IX Item "GIT_SUBREPO_COMMAND"
|
||||
This variable is exported when \f(CW\*(C`git\-subrepo\*(C'\fR is running. It is set to the
|
||||
name of the \f(CW\*(C`git\-subrepo\*(C'\fR subcommand that is running.
|
||||
.ie n .IP """GIT_SUBREPO_PAGER""" 4
|
||||
.el .IP "\f(CWGIT_SUBREPO_PAGER\fR" 4
|
||||
.IX Item "GIT_SUBREPO_PAGER"
|
||||
Use this to specify the pager to use for long output commands. Defaults to
|
||||
\&\f(CW$PAGER\fR or \f(CW\*(C`less\*(C'\fR.
|
||||
.ie n .IP """GIT_SUBREPO_QUIET""" 4
|
||||
.el .IP "\f(CWGIT_SUBREPO_QUIET\fR" 4
|
||||
.IX Item "GIT_SUBREPO_QUIET"
|
||||
Set this for quiet (\f(CW\*(C`\-q\*(C'\fR) output.
|
||||
.ie n .IP """GIT_SUBREPO_VERBOSE""" 4
|
||||
.el .IP "\f(CWGIT_SUBREPO_VERBOSE\fR" 4
|
||||
.IX Item "GIT_SUBREPO_VERBOSE"
|
||||
Set this for verbose (\f(CW\*(C`\-v\*(C'\fR) output.
|
||||
.ie n .IP """GIT_SUBREPO_DEBUG""" 4
|
||||
.el .IP "\f(CWGIT_SUBREPO_DEBUG\fR" 4
|
||||
.IX Item "GIT_SUBREPO_DEBUG"
|
||||
Set this for debugging (\f(CW\*(C`\-d\*(C'\fR) output.
|
||||
.SH "Installation Instructions"
|
||||
.IX Header "Installation Instructions"
|
||||
There are currently 3 ways to install \f(CW\*(C`git\-subrepo\*(C'\fR. For all of them you need
|
||||
to get the source code from GitHub:
|
||||
.PP
|
||||
.Vb 1
|
||||
\& git clone https://github.com/ingydotnet/git\-subrepo /path/to/git\-subrepo
|
||||
.Ve
|
||||
.PP
|
||||
The first installation method is preferred: \f(CW\*(C`source\*(C'\fR the \f(CW\*(C`.rc\*(C'\fR file. Just
|
||||
add a line like this one to your shell startup script:
|
||||
.PP
|
||||
.Vb 1
|
||||
\& source /path/to/git\-subrepo/.rc
|
||||
.Ve
|
||||
.PP
|
||||
That will modify your \f(CW\*(C`PATH\*(C'\fR and \f(CW\*(C`MANPATH\*(C'\fR, and also enable command
|
||||
completion.
|
||||
.PP
|
||||
The second method is to do these things by hand. This might afford you more
|
||||
control of your shell environment. Simply add the \f(CW\*(C`lib\*(C'\fR and \f(CW\*(C`man\*(C'\fR
|
||||
directories to your \f(CW\*(C`PATH\*(C'\fR and \f(CW\*(C`MANPATH\*(C'\fR:
|
||||
.PP
|
||||
.Vb 3
|
||||
\& export GIT_SUBREPO_ROOT="/path/to/git\-subrepo"
|
||||
\& export PATH="/path/to/git\-subrepo/lib:$PATH"
|
||||
\& export MANPATH="/path/to/git\-subrepo/man:$MANPATH"
|
||||
.Ve
|
||||
.PP
|
||||
See below for info on how to turn on Command Completion.
|
||||
.PP
|
||||
The third method is a standard system install, which puts \f(CW\*(C`git\-subrepo\*(C'\fR next
|
||||
to your other git commands:
|
||||
.PP
|
||||
.Vb 1
|
||||
\& make install # Possibly with \*(Aqsudo\*(Aq
|
||||
.Ve
|
||||
.PP
|
||||
This method does not account for upgrading and command completion yet.
|
||||
.SS "Windows"
|
||||
.IX Subsection "Windows"
|
||||
This command is known to work in these Windows environments:
|
||||
.IP "\(bu" 4
|
||||
Git for Windows \*(-- <https://git\-for\-windows.github.io/>
|
||||
.IP "\(bu" 4
|
||||
Babun \*(-- <http://babun.github.io/>
|
||||
.IP "\(bu" 4
|
||||
Cygwin \*(-- <https://www.cygwin.com/>
|
||||
.PP
|
||||
Let us know if there are others that it works (or doesn't work) in.
|
||||
.SH "Testing"
|
||||
.IX Header "Testing"
|
||||
The \f(CW\*(C`git\-subrepo\*(C'\fR repository comes with a extensive test suite. You can
|
||||
run it with:
|
||||
.PP
|
||||
.Vb 1
|
||||
\& make test
|
||||
.Ve
|
||||
.PP
|
||||
or if you don't have \f(CW\*(C`make\*(C'\fR on your system:
|
||||
.PP
|
||||
.Vb 1
|
||||
\& prove \-v test
|
||||
.Ve
|
||||
.SH "Upgrading"
|
||||
.IX Header "Upgrading"
|
||||
If you used the \f(CW\*(C`.rc\*(C'\fR or \f(CW\*(C`PATH\*(C'\fR method of installation, just run this to
|
||||
upgrade \f(CW\*(C`git\-subrepo\*(C'\fR:
|
||||
.PP
|
||||
.Vb 1
|
||||
\& git subrepo upgrade
|
||||
.Ve
|
||||
.PP
|
||||
Or (same thing):
|
||||
.PP
|
||||
.Vb 2
|
||||
\& cd /path/to/git\-subrepo
|
||||
\& git pull
|
||||
.Ve
|
||||
.PP
|
||||
If you used \f(CW\*(C`make install\*(C'\fR method, then run this again (after \f(CW\*(C`git pull\*(C'\fR):
|
||||
.PP
|
||||
.Vb 1
|
||||
\& make install # Possibly with \*(Aqsudo\*(Aq
|
||||
.Ve
|
||||
.SH "Command Completion"
|
||||
.IX Header "Command Completion"
|
||||
The \f(CW\*(C`git subrepo\*(C'\fR command supports \f(CW\*(C`<TAB>\*(C'\fR\-based command completion. If
|
||||
you don't use the \f(CW\*(C`.rc\*(C'\fR script (see Installation, above), you'll need to
|
||||
enable this manually to use it.
|
||||
.SS "In Bash"
|
||||
.IX Subsection "In Bash"
|
||||
If your Bash setup does not already provide command completion for Git, you'll
|
||||
need to enable that first:
|
||||
.PP
|
||||
.Vb 1
|
||||
\& source <Git completion script>
|
||||
.Ve
|
||||
.PP
|
||||
On your system, the Git completion script might be found at any of the
|
||||
following locations (or somewhere else that we don't know about):
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`/etc/bash_completion.d/git\*(C'\fR
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`/usr/share/bash\-completion/git\*(C'\fR
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`/usr/share/bash\-completion/completions/git\*(C'\fR
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`/opt/local/share/bash\-completion/completions/git\*(C'\fR
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`/usr/local/etc/bash_completion.d/git\*(C'\fR
|
||||
.IP "\(bu" 4
|
||||
\&\f(CW\*(C`~/.homebrew/etc/bash_completion.d/git\*(C'\fR
|
||||
.PP
|
||||
In case you can't find any of these, this repository contains a copy of the
|
||||
Git completion script:
|
||||
.PP
|
||||
.Vb 1
|
||||
\& source /path/to/git\-subrepo/share/git\-completion.bash
|
||||
.Ve
|
||||
.PP
|
||||
Once Git completion is enabled (whether you needed to do that manually or
|
||||
not), you can turn on \f(CW\*(C`git\-subrepo\*(C'\fR completion with a command like this:
|
||||
.PP
|
||||
.Vb 1
|
||||
\& source /path/to/git\-subrepo/share/completion.bash
|
||||
.Ve
|
||||
.SS "In zsh"
|
||||
.IX Subsection "In zsh"
|
||||
In the Z shell (zsh), you can manually enable \f(CW\*(C`git\-subrepo\*(C'\fR completion by
|
||||
adding the following line to your \f(CW\*(C`~/.zshrc\*(C'\fR, \fBbefore\fR the \f(CW\*(C`compinit\*(C'\fR
|
||||
function is called:
|
||||
.PP
|
||||
.Vb 1
|
||||
\& fpath=(\*(Aq/path/to/git\-subrepo/share/zsh\-completion\*(Aq $fpath)
|
||||
.Ve
|
||||
.SH "Status"
|
||||
.IX Header "Status"
|
||||
The git-subrepo command has been in use for well over a year and seems to get
|
||||
the job done. Development is still ongoing but mostly just for fixing bugs.
|
||||
.PP
|
||||
Trying subrepo out is simple and painless (this is not \f(CW\*(C`git submodule\*(C'\fR).
|
||||
Nothing is permanent (if you do not push to shared remotes). ie You can always
|
||||
play around and reset back to the beginning without pain.
|
||||
.PP
|
||||
This command has a test suite (run \f(CW\*(C`make test\*(C'\fR), but surely has many bugs. If
|
||||
you have expertise with Git and subcommands, please review the code, and file
|
||||
issues on anything that seems wrong.
|
||||
.PP
|
||||
If you want to chat about the \f(CW\*(C`git\-subrepo\*(C'\fR command, join \f(CW\*(C`#gitcommands\*(C'\fR on
|
||||
\&\f(CW\*(C`irc.freenode.net\*(C'\fR.
|
||||
.SH "Notes"
|
||||
.IX Header "Notes"
|
||||
.IP "\(bu" 4
|
||||
Works on \s-1POSIX\s0 systems: Linux, \s-1BSD, OSX,\s0 etc.
|
||||
.IP "\(bu" 4
|
||||
Works on various Windows environments. See \*(L"Windows\*(R" section above.
|
||||
.IP "\(bu" 4
|
||||
The \f(CW\*(C`git\-subrepo\*(C'\fR repo itself has 2 subrepos under the \f(CW\*(C`ext/\*(C'\fR subdirectory.
|
||||
.IP "\(bu" 4
|
||||
Written in (very modern) Bash, with full test suite. Take a look.
|
||||
.IP "\(bu" 4
|
||||
A \f(CW\*(C`.gitrepo\*(C'\fR file never is in the top level dir (next to a \f(CW\*(C`.git/\*(C'\fR dir).
|
||||
.SH "Authors"
|
||||
.IX Header "Authors"
|
||||
.IP "\(bu" 4
|
||||
Ingy döt Net <ingy@ingy.net>
|
||||
.IP "\(bu" 4
|
||||
Magnus Carlsson <grimmymail@gmail.com>
|
||||
.SH "License and Copyright"
|
||||
.IX Header "License and Copyright"
|
||||
The \s-1MIT\s0 License (\s-1MIT\s0)
|
||||
.PP
|
||||
Copyright (c) 2013\-2020 Ingy döt Net
|
||||
12
build/git-subrepo/note/0.4.0
Normal file
12
build/git-subrepo/note/0.4.0
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
- Update docs
|
||||
- Review issue/142
|
||||
- Compare operations to master
|
||||
- Add a --no-push or --dry-run flag for push
|
||||
- Add a --rebase option for push
|
||||
- Add --message= and --edit to the init command ??
|
||||
- Also add to doc
|
||||
- Update doc for steps of pull command to include merge and rebase
|
||||
- Test squashing on pull operations
|
||||
- Update push doc after understanding it more
|
||||
- Is --rebase for pull or push?
|
||||
- Make sure docs are correct too.
|
||||
148
build/git-subrepo/note/AllGitCmds
Normal file
148
build/git-subrepo/note/AllGitCmds
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
add
|
||||
add--interactive
|
||||
am
|
||||
annotate
|
||||
apply
|
||||
archive
|
||||
bisect
|
||||
bisect--helper
|
||||
blame
|
||||
branch
|
||||
bundle
|
||||
cat-file
|
||||
check-attr
|
||||
check-ref-format
|
||||
checkout
|
||||
checkout-index
|
||||
cherry
|
||||
cherry-pick
|
||||
clean
|
||||
clone
|
||||
commit
|
||||
commit-tree
|
||||
config
|
||||
count-objects
|
||||
credential-cache
|
||||
credential-cache--daemon
|
||||
credential-store
|
||||
daemon
|
||||
describe
|
||||
diff
|
||||
diff-files
|
||||
diff-index
|
||||
diff-tree
|
||||
difftool
|
||||
difftool--helper
|
||||
fast-export
|
||||
fast-import
|
||||
fetch
|
||||
fetch-pack
|
||||
filter-branch
|
||||
fmt-merge-msg
|
||||
for-each-ref
|
||||
format-patch
|
||||
fsck
|
||||
fsck-objects
|
||||
gc
|
||||
get-tar-commit-id
|
||||
grep
|
||||
hash-object
|
||||
help
|
||||
http-backend
|
||||
http-fetch
|
||||
http-push
|
||||
hub
|
||||
imap-send
|
||||
index-pack
|
||||
init
|
||||
init-db
|
||||
instaweb
|
||||
log
|
||||
lost-found
|
||||
ls-files
|
||||
ls-remote
|
||||
ls-tree
|
||||
mailinfo
|
||||
mailsplit
|
||||
merge
|
||||
merge-base
|
||||
merge-file
|
||||
merge-index
|
||||
merge-octopus
|
||||
merge-one-file
|
||||
merge-ours
|
||||
merge-recursive
|
||||
merge-resolve
|
||||
merge-subtree
|
||||
merge-tree
|
||||
mergetool
|
||||
mktag
|
||||
mktree
|
||||
mv
|
||||
name-rev
|
||||
notes
|
||||
pack-objects
|
||||
pack-redundant
|
||||
pack-refs
|
||||
patch-id
|
||||
peek-remote
|
||||
prune
|
||||
prune-packed
|
||||
pull
|
||||
push
|
||||
quiltimport
|
||||
read-tree
|
||||
rebase
|
||||
receive-pack
|
||||
reflog
|
||||
relink
|
||||
remote
|
||||
remote-ext
|
||||
remote-fd
|
||||
remote-ftp
|
||||
remote-ftps
|
||||
remote-http
|
||||
remote-https
|
||||
remote-testgit
|
||||
remove-submodule
|
||||
repack
|
||||
replace
|
||||
repo-config
|
||||
request-pull
|
||||
rerere
|
||||
reset
|
||||
rev-list
|
||||
rev-parse
|
||||
revert
|
||||
rm
|
||||
send-pack
|
||||
sh-i18n--envsubst
|
||||
shell
|
||||
shortlog
|
||||
show
|
||||
show-branch
|
||||
show-index
|
||||
show-ref
|
||||
stage
|
||||
stash
|
||||
status
|
||||
stripspace
|
||||
submodule
|
||||
subrepo
|
||||
subtree
|
||||
symbolic-ref
|
||||
tag
|
||||
tar-tree
|
||||
unpack-file
|
||||
unpack-objects
|
||||
update-index
|
||||
update-ref
|
||||
update-server-info
|
||||
upload-archive
|
||||
upload-pack
|
||||
var
|
||||
verify-pack
|
||||
verify-tag
|
||||
web--browse
|
||||
whatchanged
|
||||
write-tree
|
||||
32
build/git-subrepo/note/Cases
Normal file
32
build/git-subrepo/note/Cases
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
== Users
|
||||
|
||||
- art — project lead
|
||||
- bob — end user
|
||||
- cab — collab dev (push rights)
|
||||
- dim — forker dev (no push rights)
|
||||
- ell — third party repo owner
|
||||
|
||||
== Repos
|
||||
- art/gallery — art's main repo
|
||||
- art/painting — subrepo owned by art
|
||||
- ell/tickets — subrepo owned by ell
|
||||
|
||||
== Starting histories:
|
||||
- art/gallery — A---B
|
||||
- art/painting — P---Q
|
||||
- ell/tickets — T
|
||||
|
||||
== Scenario 1
|
||||
art art/gallery$ git log
|
||||
A---B
|
||||
art art/gallery$ git subrepo clone art/painting
|
||||
art art/gallery$ ls
|
||||
painting/
|
||||
art art/gallery$ git log
|
||||
A---B---C
|
||||
/
|
||||
Q'
|
||||
art art/gallery$
|
||||
|
||||
|
||||
|
||||
33
build/git-subrepo/note/Commands
Normal file
33
build/git-subrepo/note/Commands
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
$$$ for cmd in `cat AllGitCmds`; do git help $cmd; done
|
||||
|
||||
|
||||
== Inteesting Plumbing Commands:
|
||||
- git ls-tree HEAD
|
||||
- git cat-file -t <object>
|
||||
- git cat-file commit <commit>
|
||||
- git cat-file -p <commit>
|
||||
- git ls-tree <tree>
|
||||
- git ls-files --stage
|
||||
- git write-tree
|
||||
- git update-ref refs/heads/master <commit>
|
||||
- git symbolic-ref HEAD refs/heads/master
|
||||
- git show-branch
|
||||
- git hash-object <file>
|
||||
|
||||
- git rev-list --max-parents=0 HEAD — Find root commit
|
||||
- git cherry — find commits in one branch that are not in another
|
||||
- git replace
|
||||
|
||||
== Commands with DAG diagrams in their manpages:
|
||||
|
||||
- git-commit
|
||||
- git-filter-branch
|
||||
- git-log
|
||||
- git-merge
|
||||
- git-merge-base
|
||||
- git-pull
|
||||
- git-push
|
||||
- git-rebase
|
||||
- git-rerere
|
||||
- git-rev-list
|
||||
- git-rev-parse
|
||||
199
build/git-subrepo/note/Dags
Normal file
199
build/git-subrepo/note/Dags
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
== ASCII commmit DAG diagrams
|
||||
|
||||
D--E--F--G--H
|
||||
/ /
|
||||
A--B-----C
|
||||
|
||||
.-A---M---N---O---P
|
||||
/ / / / /
|
||||
I B C D E
|
||||
\ / / / /
|
||||
`-------------'
|
||||
|
||||
.-A---N---O
|
||||
/ / /
|
||||
I---------D
|
||||
|
||||
.-A---M---N---O---P
|
||||
/ / / / /
|
||||
I B / D /
|
||||
\ / / / /
|
||||
`-------------'
|
||||
|
||||
.-A---M---N---O
|
||||
/ / /
|
||||
I B D
|
||||
\ / /
|
||||
`---------'
|
||||
|
||||
D---E-------F
|
||||
/ \ \
|
||||
B---C---G---H---I---J
|
||||
/ \
|
||||
A-------K---------------L--M
|
||||
|
||||
E-------F
|
||||
\ \
|
||||
G---H---I---J
|
||||
\
|
||||
L--M
|
||||
|
||||
A---B---C topic
|
||||
/
|
||||
D---E---F---G master
|
||||
|
||||
|
||||
A---B---C topic
|
||||
/ \
|
||||
D---E---F---G---H master
|
||||
|
||||
o---o---o---B
|
||||
/
|
||||
---o---1---o---o---o---A
|
||||
|
||||
o---o---o---o---C
|
||||
/
|
||||
/ o---o---o---B
|
||||
/ /
|
||||
---2---1---o---o---o---A
|
||||
|
||||
o---o---o---o---o
|
||||
/ \
|
||||
/ o---o---o---o---M
|
||||
/ /
|
||||
---2---1---o---o---o---A
|
||||
|
||||
---1---o---A
|
||||
\ /
|
||||
X
|
||||
/ \
|
||||
---2---o---o---B
|
||||
|
||||
A---B---C master on origin
|
||||
/
|
||||
D---E---F---G master
|
||||
|
||||
A---B---C remotes/origin/master
|
||||
/ \
|
||||
D---E---F---G---H master
|
||||
|
||||
B
|
||||
/
|
||||
---X---A
|
||||
|
||||
B---C
|
||||
/ /
|
||||
---X---A
|
||||
|
||||
B D
|
||||
/ /
|
||||
---X---A
|
||||
|
||||
o---o---o---A---B origin/master
|
||||
\
|
||||
X---Y---Z dev
|
||||
|
||||
A---B (unnamed branch)
|
||||
/
|
||||
o---o---o---X---Y---Z master
|
||||
|
||||
A---B---C topic
|
||||
/
|
||||
D---E---F---G master
|
||||
|
||||
A'--B'--C' topic
|
||||
/
|
||||
D---E---F---G master
|
||||
|
||||
A---B---C topic
|
||||
/
|
||||
D---E---A'---F master
|
||||
|
||||
B'---C' topic
|
||||
/
|
||||
D---E---A'---F master
|
||||
|
||||
o---o---o---o---o master
|
||||
| \
|
||||
| o'--o'--o' topic
|
||||
\
|
||||
o---o---o---o---o next
|
||||
|
||||
H---I---J topicB
|
||||
/
|
||||
E---F---G topicA
|
||||
/
|
||||
A---B---C---D master
|
||||
|
||||
H'--I'--J' topicB
|
||||
/
|
||||
| E---F---G topicA
|
||||
|/
|
||||
A---B---C---D master
|
||||
|
||||
E---F---G---H---I---J topicA
|
||||
|
||||
E---H'---I'---J' topicA
|
||||
|
||||
X
|
||||
\
|
||||
A---M---B
|
||||
/
|
||||
---o---O---P---Q
|
||||
|
||||
o---o---o---o---o---o---o---o---o master
|
||||
\
|
||||
o---o---o---o---o subsystem
|
||||
\
|
||||
*---*---* topic
|
||||
|
||||
o---o---o---o---o---o---o---o master
|
||||
\ \
|
||||
o---o---o---o---o o'--o'--o'--o'--o' subsystem
|
||||
\
|
||||
*---*---* topic
|
||||
|
||||
o---o---o---o---o---o---o---o master
|
||||
\ \
|
||||
o---o---o---o---o o'--o'--o'--o'--o'--M subsystem
|
||||
\ /
|
||||
*---*---*-..........-*--* topic
|
||||
|
||||
o---o---o---o---o---o---o---o master
|
||||
\
|
||||
o'--o'--o'--o'--o' subsystem
|
||||
\
|
||||
*---*---* topic
|
||||
o---*---o topic
|
||||
/
|
||||
o---o---o---*---o---o master
|
||||
|
||||
o---*---o---+ topic
|
||||
/ /
|
||||
o---o---o---*---o---o master
|
||||
|
||||
o---*---o---+---o---o topic
|
||||
/ / \
|
||||
o---o---o---*---o---o---o---o---+ master
|
||||
|
||||
o---*---o-------o---o topic
|
||||
/
|
||||
o---o---o---*---o---o---o---o master
|
||||
|
||||
$ git rebase master topic
|
||||
|
||||
o---*---o-------o---o topic
|
||||
/
|
||||
o---o---o---*---o---o---o---o master
|
||||
|
||||
G H I J
|
||||
\ / \ /
|
||||
D E F
|
||||
\ | / \
|
||||
\ | / |
|
||||
\|/ |
|
||||
B C
|
||||
\ /
|
||||
\ /
|
||||
A
|
||||
|
||||
7
build/git-subrepo/note/Gists
Normal file
7
build/git-subrepo/note/Gists
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
- https://gist.github.com/kentfredric/9285653
|
||||
|
||||
- https://gist.github.com/anonymous/55bcf30acab99308714b
|
||||
# a + b = o
|
||||
- https://gist.github.com/anonymous/0544b465c57f01f8c4a6
|
||||
- https://gist.github.com/ingydotnet/bf92949734b6a23f2af6
|
||||
- https://gist.github.com/ingydotnet/a61b3cd1c422a17c6e5d
|
||||
25
build/git-subrepo/note/Links
Normal file
25
build/git-subrepo/note/Links
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
- http://stackoverflow.com/questions/1186535/how-to-modify-a-specified-commit/
|
||||
- http://git-scm.com/book/en/Git-Tools-Rewriting-History
|
||||
- http://git.661346.n2.nabble.com/Editing-the-root-commit-td7561714.html
|
||||
- http://stackoverflow.com/questions/645450/git-how-to-insert-a-commit-as-the-first-shifting-all-the-others
|
||||
- http://stackoverflow.com/questions/6149520/git-remove-root-commit ***
|
||||
- http://fourkitchens.com/blog/2009/01/19/creating-common-branch-ancestry-hard-problem
|
||||
- http://stackoverflow.com/questions/1488753/how-to-merge-two-branches-without-a-common-ancestor
|
||||
- http://sahd.lamafam.org/?p=1534
|
||||
|
||||
- http://www.claassen.net/geek/blog/2011/02/git-merge-strategytheirs.html
|
||||
- sahd.lamafam.org/?p=1534
|
||||
- http://stackoverflow.com/questions/2945344/selecting-merge-strategy-options-for-git-rebase
|
||||
- http://stackoverflow.com/questions/2428137/how-to-rebase-one-git-repository-onto-another-one
|
||||
- http://stackoverflow.com/questions/3080509/git-list-commits-not-pushed-to-the-origin-yet
|
||||
- http://stackoverflow.com/questions/2263674/how-do-i-find-the-next-commit-in-git
|
||||
|
||||
- http://git-scm.com/book/ch6-7.html (Subtree Merge)
|
||||
- https://www.kernel.org/pub/software/scm/git/docs/howto/using-merge-subtree.html
|
||||
- https://help.github.com/articles/working-with-subtree-merge
|
||||
- git pull -s subtree foo master
|
||||
|
||||
- http://git-scm.com/2010/03/17/replace.html
|
||||
|
||||
- http://git.661346.n2.nabble.com/subtree-merges-lose-prefix-after-rebase-td7332850.html
|
||||
- http://ruleant.blogspot.com/2013/06/git-subtree-module-with-gittrees-config.html
|
||||
10
build/git-subrepo/note/Plugins
Normal file
10
build/git-subrepo/note/Plugins
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
- https://github.com/nothingmuch/git-svn-abandon
|
||||
- https://github.com/schacon?tab=repositories
|
||||
- https://github.com/jbalogh/git-tools
|
||||
- https://github.com/wesabe/git-tools
|
||||
- https://github.com/timcharper/git-helpers
|
||||
- https://github.com/schacon/git-pulls
|
||||
- https://github.com/node-gh/gh
|
||||
- https://github.com/splitbrain/git-pull-request
|
||||
- https://github.com/mloughran/git-cleanup
|
||||
- https://github.com/seveas/git-hub
|
||||
39
build/git-subrepo/note/Spec
Normal file
39
build/git-subrepo/note/Spec
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
= `git-hub` Design Specification
|
||||
|
||||
== Main Commands
|
||||
|
||||
- `clone`
|
||||
|
||||
git subrepo clone <git-url> <subdir> [<options>]
|
||||
|
||||
- `pull`
|
||||
|
||||
- `push`
|
||||
|
||||
== Worker Commands
|
||||
|
||||
- `fetch`
|
||||
|
||||
git subrepo fetch <subdir>
|
||||
|
||||
- `branch`
|
||||
|
||||
- `checkout`
|
||||
|
||||
- `commit`
|
||||
|
||||
- `reset`
|
||||
|
||||
== Info Commands
|
||||
|
||||
- `status`
|
||||
|
||||
- `log`
|
||||
|
||||
== Other Commands
|
||||
|
||||
- `clean`
|
||||
|
||||
- `help`
|
||||
|
||||
- `version`
|
||||
57
build/git-subrepo/note/Story1
Normal file
57
build/git-subrepo/note/Story1
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
== git subrepo clone git@genius --branch=bob ext/genius
|
||||
|
||||
- create orphan branch repo/genius
|
||||
- fetch git@genius --branch=bob
|
||||
- create local branch repo/genius
|
||||
- checkout repo/genius into ext/genius
|
||||
- SYNC-DANCE:
|
||||
- add ext/genius/.gitrepo
|
||||
- commit the add and prune the commit
|
||||
- merge the pruned commit into mianline
|
||||
|
||||
== git subrepo pull ext/genius
|
||||
|
||||
- checkout ext/genius
|
||||
- fetch git@genius --branch=bob
|
||||
- merge/rebase FETCH_HEAD
|
||||
- commit if merge successful
|
||||
- checkout original branch
|
||||
- SYNC-DANCE
|
||||
|
||||
== git subrepo branch ext/genius
|
||||
- filter-branch subdir ext/genius
|
||||
- filter-branch 'rm .gitrepo'
|
||||
- add parent of original
|
||||
- name the commit subrepo/ext/genius
|
||||
|
||||
== git subrepo checkout ext/genius
|
||||
- subrepo branch ext/genius
|
||||
- checkout subrepo/ext/genius
|
||||
|
||||
== git subrepo push ext/genius
|
||||
- subrepo branch ext/genius
|
||||
- checkout repo/genius
|
||||
- merge/rebase subrepo/ext/genius
|
||||
- push repo/genius git@genius/bob
|
||||
- checkout original
|
||||
|
||||
|
||||
= Commands =
|
||||
|
||||
git subrepo clone git@github.com:ingydotnet/bashplus.git
|
||||
git subrepo clone git@github.com:ingydotnet/bashplus.git ext/bashplus
|
||||
git subrepo clone git@github.com:ingydotnet/bashplus.git --branch=devel
|
||||
git subrepo clone git@github.com:ingydotnet/bashplus.git --reclone
|
||||
|
||||
|
||||
git subrepo pull git@github.com:ingydotnet/bashplus.git
|
||||
git subrepo pull git@github.com:ingydotnet/bashplus.git --branch=master
|
||||
git subrepo pull git@github.com:ingydotnet/bashplus.git --rebase
|
||||
|
||||
git subrepo branch ext/bashplus # create refs/heads/subrepo/ext/bashplus
|
||||
|
||||
git subrepo checkout ext/bashplus
|
||||
|
||||
git subrepo push ext/bashplus
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue