- Gitbar 1 1 3 – Remind You Of Uncommitted Repository Download
- Gitbar 1 1 3 – Remind You Of Uncommitted Repository List
- Gitbar 1 1 3 – Remind You Of Uncommitted Repository Full
- Gitbar 1 1 3 – Remind You Of Uncommitted Repository Search
A git choose-your-own-adventure!
GitBar will remind you of uncommitted repository during the day when you forget it. GitBar will watch your local git repositories and smartly send notifications when you forgot to commit your work. Use the today widget during the day to quickly check if some modification is not safely committed. GitBar will remind you of uncommitted repository during the day when you forget it. GitBar will watch your local git repositories and smartly send notifications when you forgot to commit your work. Use the today widget during the day to quickly check if some modification is not safely committed. GitBar-1.2.zip.torrent GitBar 1.2 – Remind you of uncommitted repository. Size: 11.19 MB GitBar will remind you of uncommitted repository. GitBar will watch your local git repositories and smartly notify when you forgot to commit your GitBar 1.2. March 2, 2017,Developer tools,GitBar,MacOs Apps.
This document is an attempt to be a fairly comprehensive guide torecovering from what you did not mean to do when using git. It isn'tthat git is so complicated that you need a large document to take careor your particular problem, it is more that the set of things that youmight have done is so large that different techniques are neededdepending on exactly what you have done and what you want to havehappen.
If you have problems after clicking through this document, pleasedocument what the links you clicked on are when asking for furtherhelp (on #git or elsewhere) which will explain very precisely what youwere trying to do and that you at least tried to help yourself.Sorry, due to the limitations of github we cannot gather the historyfor simple copy-paste.
First step
Strongly consider taking abackup of your currentworking directory and .git to avoid any possibility of losing data asa result of the use or misuse of these instructions. We promise tolaugh at you if you fail to take a backup and regret it later.
Answer the questions posed by clicking the link for that section. Asection with no links is a terminal node and you should have solvedyour problem by completing the suggestions posed by that node (if not,then report the chain of answers you made on #git or some other gitresource and explain further why the proposed answer doesn't help).This is not a document to read linearly.
## Are you trying to find that which is lost or fix a change that was made?These are the Git workflow scripts we use. They came from here and evolved to the form you see in the scripts directory. We added functions that 1) prevent you from getting latest if you have uncommitted changes, 2) remind you to work in a feature branch, and 3) automatically determine the remote branch associated with the current feature branch. I call this operation 'cherry-pit' since it is the inverse of a 'cherry-pick'. You must first identify the SHA of the commit you wish to remove. You can do this using gitk -date-order or using git log -graph -decorate -oneline You are looking for the 40 character SHA-1 hash ID (or the 7 character abbreviation). Yes, if you know the '^'.
Due to previous activities (thrashing about), you may have lost somework which you would like to find and restore. Alternately, you mayhave made some changes which you would like to fix.
## Have you committed?If you have not yet committed that which you do not want, git does notknow anything about what you have done yet, so it is pretty easy toundo what you have done.
## Everything or just some things?So you have not yet committed, the question is now whether you want toundo everything which you have done since the last commit or just somethings?
## How to undo all uncommitted changesSo you have not yet committed and you want to undo everything. Well,best practice is for you to stashthe changes in case you were mistaken and later decide that you reallywanted them after all.
git stash save 'description of changes'
. Youcan revisit those stashes later git stash list
and decide whether togit stash drop
them after some time has past. Please note thatuntracked and ignored files are not stashed by default. See'--include-untracked' and '--all' for stash options to handle thosetwo cases.However, perhaps you are confident (or arrogant) enough to know forsure that you will never ever want the uncommitted changes. If so,you can run
## How to undo some uncommitted changesgit reset --hard
, however please be quite aware thatthis is almost certainly a completely unrecoverable operation. Anychanges which are removed here cannot be restored later. This willnot delete untracked or ignored files. Those can be deleted with git clean -nd
git clean -ndX
respectively, or git clean -ndx
for bothat once. Well, actually those command do not delete the files. Theyshow what files will be deleted. Replace the 'n' in '-nd…' with 'f'to actually delete the files. Bestpractice is to ensure you are notdeleting what you should not by looking at the moribund filenamesfirst.So you have not yet committed and you want to undo some things, well
git status
will tell you exactly what you need to do. For example:However, the
## Do you have a clean working directory?git checkout
in file mode is a command that cannot berecovered from—the changes which are discarded most probably cannot berecovered. Perhaps you should run git stash save -p 'description'
instead, and select the changes you no longer want to be stashedinstead of zapping them.So you have committed. However, before we go about fixing or removingwhatever is wrong, you should first ensure that any uncommittedchanges are safe, by either committing them (
## Have you pushed?git commit
) or bystashing them (git stash save 'message'
) or getting rid of them.git status
will help you understand whether your working directoryis clean or not.So you have committed, the question is now whether you have made yourchanges publicly available or not. Publishing history is seminalevent.
Please note in any and all events, the recipes provided here willtypically (only one exception which will self-notify) only modify thecurrent branch you are on. Specifically any tags or branchesinvolving the commit you are changing or a child or that commit willnot be modified. You must deal with those separately. Look at
gitk --all --date-order
to help visualize everything what other gitreferences might need to be updated.Also note that these commands will fix up the referenced commits inyour repository. There will be reflog'd and dangling commits holdingthe state you just corrected. This is normally a good thing and itwill eventually go away by itself, but if for some reason you want tocut your seat belts, you can expire the reflog now and garbage collectwith immediate pruning.
## Do you want to discard all unpushed changes on this branch?There is a shortcut in case you want to discard all changes made onthis branch since you have last pushed or in any event, to make yourlocal branch identical to 'upstream'. Upstream, for local trackingbranches, is the place you get history from when you
## Discarding all local commits on this branchgit pull
:typically for master it might be origin/master. There is a variant ofthis option which lets you make your local branch identical to someother branch or ref.In order to discard all local commits on this branch, to make thelocal branch identical to the 'upstream' of this branch, simply run
## Replacing all branch history/contentsgit reset --hard @{u}
If instead of discarding all local commits, you can make your branchidentical to some other branch, tag, ref, or SHA that exists on yoursystem.
The first thing you need to do is identify the SHA or ref of the goodstate of your branch. You can do this by looking at the output of
git branch -a; git tag
, git log --all
or, my preference, you canlook graphically at gitk --all --date-order
Once you have found the correct state of your branch, you can get tothat state by running
Obviously replace 'ref' in both commands with the reference or SHA youwant to get back to.
## Is the commit you want to fix the most recent?While the techniques mentioned to deal with deeper commits will workon the most recent, there are some convenient shortcuts you can takewith the most recent commit.
## Do you want to remove or change the commit message/contents of the last commit?## Removing the last commitTo remove the last commit from git, you can simply run
git reset --hard HEAD^
If you are removing multiple commits from the top, youcan run git reset HEAD~2
to remove the last two commits. You canincrease the number to remove even more commits.If you want to save the commits on a new branch name, then run
## Updating the last commit's contents or commit messagegit branch newbranchname
BEFORE doing the git reset
.To update the last commit's contents, author, or commit message for acommit which you have not pushed or otherwise published, first youneed to get the index into the correct state you wish the commit toreflect. If you are changing the commit message only, you need donothing. If you are changing the file contents, typically you wouldmodify the working directory and use
git add
as normal.Note if you wish to restore a file to a known good state, you can use
git checkout GOODSHA -- path/to/filename
.Once the index is in the correct state, then you can run
## Do you want to remove an entire commit?## Removing an entire commitgit commit --amend
to update the last commit. Yes, you can use '-a' if you wantto avoid the git add
suggested in the previous paragraph. You canalso use --author to change the author information.I call this operation 'cherry-pit' since it is the inverse of a'cherry-pick'. You must first identify the SHA of the commit youwish to remove. You can do this using
gitk --date-order
or usinggit log --graph --decorate --oneline
You are looking for the 40character SHA-1 hash ID (or the 7 character abbreviation). Yes, ifyou know the '^' or '~' shortcuts you may use those.Obviously replace 'SHA' with the reference you want to get rid of.The '^' in that command is literal.
However, please be warned. If some of the commits between SHA and thetip of your branch are merge commits, it is possible that
## Do you want to remove/change/rename a particular file/directory from all commits during all of git's history## Changing all commits during all of git's historygit rebase -p
will be unable to properly recreate them. Please inspect theresulting merge topology gitk --date-order HEAD ORIG_HEAD
to ensurethat git did want you wanted. If it did not, there is not really anyautomated recourse. You can reset back to the commit before the SHAyou want to get rid of, and then cherry-pick the normal commits andmanually re-merge the 'bad' merges. Or you can just suffer with theinappropriate topology (perhaps creating fake merges git merge --ours otherbranch
so that subsequent development work on those brancheswill be properly merged in with the correct merge-base).Gitbar 1 1 3 – Remind You Of Uncommitted Repository Download
You have not pushed but still somehow want to change all commits inall of git's history? Strange.
You want to use the
git filter-branch
command to perform thisaction. This command is quite involved and complex, so I will simplypoint you at the manual pageand remind you that best practiceis to always use --tag-name-filter cat -- --all
unless you arereally sure you know what you are doing.BTW, this is the one command I referred to earlier which will updateall tags and branches, at least if you use the best practicearguments.
## Is a merge commit involved?If the commit you are trying to change is a merge commit, or if thereis a merge commit between the commit you are trying to change and thetip of the branch you are on, then you need to do some specialhandling of the situation.
## Changing a single commit involving only simple commitsYou must first identify the SHA of the commit you wish to remove.You can do this using
gitk --date-order
or using git log --graph --decorate --oneline
You are looking for the 40 character SHA-1 hashID (or the 7 character abbreviation). Yes, if you know the '^' or '~'shortcuts you may use those.Gitbar 1 1 3 – Remind You Of Uncommitted Repository List
Obviously replace 'SHA' with the reference you want to get rid of.The '^' in that command is literal.
You will be dumped in an editor with a bunch of lines starting withpick. The oldest commit, the one you are probably interested inchanging, is first. You will want to change the 'pick' to 'reword' or'edit', or perhaps even 'squash' depending on what your goal is.Please read the manual page for moreinformation.
When using 'edit', to change contents or author, when you are dumpedinto the shell to make your change, well make your change,
## Changing a single commit involving a mergegit add
as normal, and then run git commit --amend
(including changing theauthor information with --author). When you are satisfied, you shouldrun git rebase --continue
Oh dear. This is going to get a little complicated. It should allwork out, though. You will need to use anonce branch as a placeholder.I will call the nonce branch 'nonce' in the following example.However, you may use any branch name that is not currently in use.You can delete it immediately after you are done.
- Identify the SHA of the commit you wish to modify.You can do this using
gitk --date-order
or usinggit log --graph --decorate --oneline
You are looking for the 40 character SHA-1 hashID (or the 7 character abbreviation). Yes, if you know the '^' or '~'shortcuts you may use those. - Remember the name of the branch you are currently onThe line with a star on it in the
git branch
output is the branchyou are currently on. I will use '$master' in this example, butsubstitute your branch name for '$master' in the following commands. - Create and checkout a nonce branch pointing at that commit.
git checkout nonce SHA
- Validate that the topology is still goodIf some of the commits after the commit you changed are merge commits,please be warned. It is possible that
git rebase -p
will be unable toproperly recreate them. Please inspect the resulting merge topologygitk --date-order HEAD ORIG_HEAD
to ensure that git did want youwanted. If it did not, there is not really any automated recourse.You can reset back to the commit before the SHA you want to get ridof, and then cherry-pick the normal commits and manually re-merge the'bad' merges. Or you can just suffer with the inappropriate topology(perhaps creating fake mergesgit merge --ours otherbranch
so thatsubsequent development work on those branches will be properly mergedin with the correct merge-base). - Delete the nonce branchYou don't need it. It was just there to communicate an SHA betweentwo steps in the above process.
git branch -d nonce
Rewriting public history is a badidea. It requires everyoneelse to do special things and you must publicly announce your failure.Ideally you will create either a commit to just fix the problem, or anew
## Making a new commit to fix an old commitgit revert
commit to create a new commit which undoes what thecommit target of the revert did.If the problem in the old commit is just something was doneincorrectly, go ahead and make a normal commit to fix the problem.Feel free to reference the old commit SHA in the commit message, andif you are into the blame-based development methodology, make fun ofthe person who made the mistake (or someone who recently left if youmade the mistake).
## Making a new commit to restore a file deleted earlierThe file may have been deleted or every change to that file in thatcommit (and all commits since then) should be destroyed. If so, youcan simply checkout a version of the file which you know is good.
You must first identify the SHA of the commit containing the goodversion of the file. You can do this using
gitk --date-order
orusing git log --graph --decorate --oneline
You are looking for the40 character SHA-1 hash ID (or the 7 character abbreviation). Yes, ifyou know the '^' or '~' shortcuts you may use those.Gitbar 1 1 3 – Remind You Of Uncommitted Repository Full
Obviously replace 'SHA' with the reference that is good.You can then add and commit as normal to fix the problem.
## Reverting an old simple pushed commitTo create an positive commit to remove the effects of a simple(non-merge) commit, you must first identify the SHA of the commit youwant to revert. You can do this using
gitk --date-order
or usinggit log --graph --decorate --oneline
You are looking for the 40character SHA-1 hash ID (or the 7 character abbreviation). Yes, ifyou know the '^' or '~' shortcuts you may use those.Obviously replace 'SHA' with the reference you want to revert.
## Reverting a merge commitOh dear. This is going to get complicated.
To create an positive commit to remove the effects of a merge commit,you must first identify the SHA of the commit you want to revert. Youcan do this using
gitk --date-order
or using git log --graph --decorate --oneline
You are looking for the 40 character SHA-1 hashID (or the 7 character abbreviation). Yes, if you know the '^' or '~'shortcuts you may use those.Undoing the file modifications caused by the merge is about as simpleas you might hope.
git revert SHA
. Unfortunately, this is just thetip of the iceberg. The problem is, what happens if you want to mergethat branch later, perhaps months later long after you have exiledthis problem from your memory, either to this branch or to some otherbranch this branch merged into. Well, the problem is git has ittracked in history that a merge occurred, so it is not going toattempt to remerge what it has already merged. The fact that it waslater reverted is irrelevant. You could revert the revert, but thatsupposes that you remember that you need to do so.Another option is to abandon the branch you merged from, recreate itfrom the previous merge-base with the commits since then rebased orcherry-picked over, and use the recreated branch from now on. Thenthe new branch is unrelated and will merge properly. Of course, ifyou have pushed the donor branch you cannot use the same name (thatwould be rewriting public history and is bad) so everyone needs toremember to use the new branch. Hopefully you have something likegitolite where you can closethe old branch name.
At this time, I will not walk you through the process of recreatingthe donor branch. Given sufficient demand I can try to add that.However, if you look at howto/revert-a-faulty-merge.txt which isshipped as part of the git distribution, it will provide more wordsthan you can shake a stick at.
## Rewriting an old branch with a new branch with a new commitIf the state of a branch is contaminated beyond repair and you havepushed that branch or otherwise do not want to rewrite the existinghistory, then you can make a new commit which overwrites the originalbranch with the new one and pretends this was due to a merge. Thecommand is a bit complicated, and will get rid of all ignored oruntracked files in your working directory, so please be sure you haveproperly backed up everything.
In the follow example please replace $destination with the name of thebranch whose contents you want to overwrite. $source should bereplaced with the name of the branch whose contents are good.
You actually are being provided with two methods. The first set ismore portable but generates two commits. The second knows about thecurrent internal files git uses to do the necessary work in onecommit. Only one command is different and a second command runs at adifferent time.
or
## I am a bad person and must rewrite published historyHopefully you read the previous reference and fully understand whythis is bad and what you have to tell everyone else to do in order torecover from this condition. Assuming this, you simply need to go tothe parts of this document which assume that you have not yet pushedand do them as normal. Then you need to do a 'force push'
git push -f
to thrust your updated history upon everyone else. As you read inthe reference, this may be denied by default by your upstreamrepository (see git config receive.denyNonFastForwards
, but can bedisabled (temporarily I suggest) if you have access to the server.You then will need to send mail to everyone who might have pulledthe history telling them that history was rewritten and they need togit pull --rebase
and do a bit of history rewriting of their own ifthey branched or tagged from the now outdated history.Proceed with fixing the old commit.
## I have lost some commits I know I madeFirst make sure that it was not on a different branch. Try
git log -Sfoo --all
where 'foo' is replaced with something unique in thecommits you made. You can also search with gitk --all --date-order
to see if anything looks likely.Check your stashes,
git stash list
, to see if you might have stashedinstead of committing. You can also run gitk --all --date-order $(git stash list | awk -F: '{print $1};')
to visualize what thestashes might be associated with.Next, you should probably look in other repositories you have lyingaround including ones on other hosts and in testing environments, andin your backups.
Once you are fully convinced that it is well and truly lost, you canstart looking elsewhere in git. Specifically, you should first lookat the reflog which contains the history of what happened to the tipof your branches for the past two weeks or so. You can of course say
git log -g
or git reflog
to view it, but it may be best visualizedwith gitk --all --date-order $(git reflog --pretty=%H)
Next you can look in git's lost and found. Dangling commits getgenerated for many good reasons including resets and rebases. Stillthose activities might have mislaid the commits you were interestedin. These might be best visualized with
gitk --all --date-order $(git fsck | grep 'dangling commit' | awk '{print $3;}')
The last place you can look is in dangling blobs. These are fileswhich have been
git add
ed but not attached to a commit for some(usually innocuous)reason. git fsck | grep 'dangling blob' | while read x x s; do git show $s | less; done
will show you the files, oneat a time.Once you find the changes you are interested in, there are severalways you can proceed. . You can
## Undoing the last few git operations affecting HEAD/my branch's tipgit reset --hard SHA
your currentbranch to the history and current state of that SHA (probably notrecommended for stashes), you can git branch newbranch SHA
to linkthe old history to a new branch name (also not recommended forstashes), you can git stash apply SHA
(for the non-index commit in agit-stash), you can git stash merge SHA
or git cherry-pick SHA
(for either part of a stash or non-stashes), etc.Practically every git operation which affects the repository isrecorded in the git reflog. You may then use the reflog to look atthe state of the branches at previous times or even go back to thestate of the local branch at the time.
While this happens for every git command affecting HEAD, it is usuallymost interesting when attempting to recover from a bad rebase orreset or an --amend'ed commit. There are better ways (listed by the rest of this document)from recovering from the more mundane reflog updates.
The first thing you need to do is identify the SHA of the good stateof your branch. You can do this by looking at the output of
git log -g
or, my preference, you can look graphically at gitk --all --date-order $(git log -g --pretty=%H)
Roadblock 1 5 8 download free. Once you have found the correct state of your branch, you can get backto that state by running
You could also link that old state to a new branch name using
Obviously replace 'SHA' in both commands with the reference you want to get back to.
Gitbar 1 1 3 – Remind You Of Uncommitted Repository Search
Note that any other commits you have performed since you did that'bad' operation will then be lost. You could
## Recovering from a borked/stupid/moribund mergegit cherry-pick
orgit rebase -p --onto
those other commits over.So, you were in the middle of a merge, have encountered one or moreconflicts, and you have now decided that it was a big mistake and wantto get out of the merge.
The fastest way out of the merge is
## Recovering from a borked/stupid/moribund rebasegit merge --abort
So, you were in the middle of a rebase, have encountered one or moreconflicts, and you have now decided that it was a big mistake and wantto get out of the merge.
The fastest way out of the merge is
## Disclaimergit rebase --abort
Information is not promised or guaranteed to be correct, current, orcomplete, and may be out of date and may contain technicalinaccuracies or typographical errors. Any reliance on this materialis at your own risk. No one assumes any responsibility (and everyoneexpressly disclaims responsibility) for updates to keep informationcurrent or to ensure the accuracy or completeness of any postedinformation. Accordingly, you should confirm the accuracy andcompleteness of all posted information before making any decisionrelated to any and all matters described.
## CopyrightCopyright ⓒ 2012 Seth Robertson
Creative Commons Attribution-ShareAlike 2.5 Generic (CC BY-SA 2.5)
I would appreciate changes being sent back to me, being notified ifthis is used or highlighted in some special way, and links beingmaintained back to the authoritative source. Thanks.
## ThanksThanks to the experts on #git and my coworkers for review, feedback,and ideas.
## CommentsComments and improvements welcome.
Add them below, or discuss with SethRobertson (and others) on #git
Line eater fodder
Because of my heavy use of anchors for navigation, and the utter lackof flexibility in the markup language this document is written in, itis important that the document be long enough at the bottom tocomplete fill your screen so that the item your link directed you tois at the top of the page.
Hopefully that should do it.
When developing with CiviCRM, one often prepares a development-build on your workstation which includes several git repositories, e.g.
- Git repositories for the official CiviCRM code (civicrm-core, civicrm-packages, and one or more of the CMS repos -- civicrm-drupal/civicrm-joomla/civicrm-wordpress)
- Git repositories for some Drupal modules, Joomla extensions, or WordPress plugins
- Git repositories for some CiviCRM extensions
Managing all these git respositories in the development-build can be challenging, and a few techniques have arisen within our community:
- Manage them all manually. This gives precise control over checkouts, branches, merges, etc., but it can be cumbersome, and it's easy to make a mistake or omission when you have more than 2 repos.
- Manage them with 'gitify' and 'givi' (which are bundled in CiviCRM). These commands help with cloning and updating code (respectively), but they only work with CiviCRM's repositories and (for givi) deviate from the 'vanilla' git workflows.
- Manage them with 'drush make --working-copy'. This is great at cloning the repos and works with any git repo. However, after hacking various repos for half a day, there's no great way to ensure that they're all clean and up-to-date -- the safe bet is to destroy and rebuild (which is slow and destroys your git remotes, git hooks, local branches, etc). And it only works with Drupal.
- Manage them with private shell scripts. This approach also works with any git repo, but it requires more scripting skills to adapt to your needs.
- (Note: Other techniques have arisen outside our community; see the footnote if the topic really interests you.)
I'd like to offer another tool -- it's not a full replacement for any of these, but it complements them. The tool is git-scan. The basic assumptions of git-scan are:
- You have already created a development build by other means (with gitify, drush-make, composer, manual checkouts, etc).
- Your development build may include a dozen repos at once, but you generally focus on one at a time.
- If you're focusing on a particular repo, then you should use normal git commands to do the work -- 'git checkout', 'git push', etc. These are the commands described in all the documentation and training materials for git.
- For all the other repos, you don't want to think too much about them. You just want to know that they've got canonical code -- ie they check out a reasonable branch, don't have any local changes, and are up-to-date.
- You don't want to write any new configuration, manifests, or metadata files that are custom to your system -- after all, that's more learning and more maintenance!
These aren't hard assumptions -- if you're spreading focus among 2-3 repos for a particular project, git-scan will still help you stay organized, but the housekeeping work will grow as you spread your attention across more repos.
Usage
For example, when I start development in the morning:
- First, I make sure that development-build is in a clean state. Were there any changes I forgot to commit yesterday? If so, I need to commit them (or stash them or discard them). Did I checkout an experimental branches? If so, I need to get back to a normal branch. But with so many repos, it's hard to remember which ones I messed around with yesterday. 'git scan status' scans for git repos and displays the status of each so that I can decide what housekeeping is needed.
- Second, I want to make sure that I have the latest code -- this helps ensure that my changes work correctly when all the developers' code comes together. 'git scan update' scans for git repos and updates each. Note: 'git scan update' is pretty conservative. If a repository has uncommitted changes, deviates from the main-line code, etc, then 'git scan update' will skip it and remind you to take care of it. (In git-speak, the command will automatically 'fast-forward' but will leave you in charge of any 'merging' or 'rebasing.')
For more details and examples, see the README.
Installation
On most Unix systems with PHP CLI, you can download the standalone Phar executable, e.g.
If you're interested in doing development, you can checkout the code and dependencies via composer:
Please note: The package hasn't been broadly tested yet -- in particular, it's mostly been used with MAMP and some flavors of Linux. You will need a working and reasonably recent/complete PHP CLI environment. If you try it in another environment, let me know if it works (or how it breaks).
Footnote: Other solutions
There are a few other solutions to the problem of managing multiple git repositories. I omitted them earlier because I haven't encountered people using them within our community, but they merit consideration. They present different trade-offs:
- git-plus includes a feature for updating multiple repos, and it generally has more actions than git-scan, but it's designed to check a single-level in the file-tree. A typical development-build based on Drupal, Joomla, or WordPress has code in many different locations in the file tree.
- mr and repo handle updates to git repos in many locations, but they require extra metadata/configuration for each repo. They also coordinate several aspects of the SCM workflow -- cloning, pulling, pushing. That is neat functionality, but (a) we have more specialized tools (drush-make, composer) which are arguably better at the cloning issue and (b) in practice, the workflows and norms for merging code vary depending on the particular repo/project. It seems unlikely that one could find any single combination of tool+metadata+workflow that allows active participation in PHP's (and CiviCRM's) diverse ecosystem.