- Mercurial’s templates seem more complete and easier to read/use than Git’s pretty format codes
- Similar to PowerShell’s handling of arguments, Mercurial will execute commands as long as you type enough characters for it to figure out what you mean (
st => status
,out => outgoing
,in => incoming
, etc). This works for aliases, too. - Mercurial’s counterpart to a Git
--bare
repository is created with the--no-update
flag - I knew Mercurial’s branches are heavier than Git’s, but I didn’t realize you actually had to close a branch (with
hg commit --close-branch
) after its changes have been merged. - TortoiseHg has a
shelve
command that’s similar togit stash
. It turns out there’s also a shelve extension apart from TortoiseHg, which the book does not mention. - Mercurial Queues are ridiculous. More on that later.
-
The Crecord extension allows you to mimic
git add --patch
.It is very similar to the use of Git’s staging area…except that you have the choice to use it (by typing
hg crecord
) or to commit everything (by typinghg commit
).N.B. The more I use it and teach it, the more I appreciate Git’s staging area. Crecord captures only a portion of its capabilities.</li> </ul>
The Bad
The overall structure of the book could work well, but I was disappointed by the execution within some important recipes. Each recipe is broken into sections: Getting Ready, How to do it, How it works, and There’s more. The recipe itself is a numbered list within How to do it, which is where things get confusing: new concepts are often introduced partway through a list, without fanfare or sufficient detail.
For example, branches were introduced in bullet #7 (of 9) in the “Branching, merging and managing conflicts” recipe. Then There’s more concludes the chapter with a two-sentence paragraph introducing Bookmarks, which “offer another way of diverging to postpone the problems of merges and conflicts,” and giving this guidance on how one should handle divergent lines of work:
To summarize, for topical temporary diversion, it is a good practice to use only clones. It helps, for switching back and forth between several lines of development in parallel, to use bookmarks; and if you need a long-term diversion, use branches.
Maybe this is enough of the Essentials for someone new to Mercurial, but I was expecting more.
My other frustration was the book’s regular use of new commands and options without any introduction or explanation. I knew enough to guess at most of them, but I found the started purpose of a particular example was often lost in my need to process the unexpected new information at the same time.
The Ugly
The Using additional commands and extensions recipe includes a discussion of Mercurial Queues. I was looking forward to the “Essential” introduction to MQ, because the GitConcepts section of the Mercurial documentation says:
If you need the index, you can gain its behavior (with many additional options) with mercurial queues (MQ).
I rather like the index, especially now that I know how
reset
works (and that it supports--patch
!), so I was curious what MQ brings to the table. In a word: confusion.hg qinit
creates a file structure under.hg/patches
with its own Mercurial repository, so patches can themselves be versioned (which seems really weird to me).hg qnew
creates a new patch, which seems like a “future commit” of sorts.hg qrefresh
applies current changes to the latest patch.- An
hg status
here shows no changes, as expected. - An
hg log -r tip
here shows a new changeset, with a tag for the patch plusqbase
,qtip
andtip
. So it seems like this is kind of a commit, it’s just not referenced by any branches/bookmarks. Apparentlytip
is always the most recent changeset, even if it’s not a real commit? I’m not convinced this is a useful distinction.
- An
hg qcommit
creates a commit within the.hg/patches
repository to save the patch changes.hq qapplied
lists patches applied since the last real commit.hg qpop
, treating patches as a stack, removes one or more patches from the working directory.hg qpush
restores one or more patches to the working directory – it’s unclear what happens if you fail toqpush
after youqpop
.- The book stops there, but apparently there’s also a
qfinish
to convert a patch into a permanent changeset.
Eight new commands with no apparent relationship to existing Hg concepts. I’ll give MQ proponents the benefit of the doubt that it can be productive, but I’m not sure how it would fit into a complete workflow with branches or bookmarks. From what I know so far, it seems like a lot of effort to make mutable commits that aren’t commits, when it would be much easier to just accept that a commit doesn’t need to be immutable until future work depends on it.
Conclusion
Ultimately, this isn’t really my kind of book — as a professional, I like to know my tools beyond just the “Essentials.” If you’re looking for a bare-minimum introduction, with a little extra, this isn’t a bad place to start, though I would be surprised if there weren’t free material online of similar quality.
- No current branch information
- No file status information
- No tab completion for new, modified or deleted files
- No tab completion for branches, shelvesets, etc
- Tab expansion for commands:
tf ch<tab>
expands totf checkout
- Tab expansion for help:
tf help ch<tab>
expands totf help checkout
- A prompt hook if someone can figure out a way to get current directory status.
- Git 1.7.2 or better is required
- And I fixed a bug that prevented it from working with 1.7.10.
- Prompt status now plays nicely with posh-hg without extra hacks
- Functions are now provided for using
ssh-agent
to save credentials- If you get a warning that
ssh-agent
could not be found, either add anssh-agent
PowerShell alias or add the path toGit\bin
in yourPATH
environment variable
- If you get a warning that
- Branch in prompt status is now colored according to being ahead of or behind a tracked reference (see readme for an explanation of default colors)
- Added tab expansion for a bunch of new commands and options (remote refs,
revert
,tfs
,bisect
,submodule
, and more!) -
Tab expansion works for aliases of
git
(I recommendg
)Contributed by Mark Borcherding
- The list of commands expanded by default now covers most porcelain commands.
- You can always get all commands to expand by setting
$GitTabSettings.AllCommands = $true
- You can always get all commands to expand by setting
- Values of
$LASTERRORCODE
for the last real command are preserved through the prompt -
If prompt performance for a repository is not acceptable, that repo’s path can be added to
$GitPromptSettings.RepositoriesInWhichToDisableFileStatus
Contributed by Eric Lee
- posh-git should work in the Nuget Package Manager Console, though you’ll probably want to change the colors
-
The
GIT_DIR
environment variable is used if definedContributed by Daniel Dabrowski
git stash
, which pushes the changes in your index and working directory onto a local stack of stashes from which you can pop at any time. Your typical workflow would look something like this: <pre>$ git stash save “I love interruptions!” $ git checkout master -b pti… save the day …
$ git checkout my-feature $ git stash pop</pre>
- Don’t run your build server as a Windows Service. I don’t like this option as it’s harder to maintain.
- Run the build service as Local System with “Allow service to interact with desktop”. This limits your ability to manipulate the context in which builds run, for example it’s quite tricky (I believe it’s possible with PsExec) to configure Internet Explorer settings (turn off Auto-Complete, etc) for LocalSystem.
$svcName = Get-Service -DisplayName *cruise* | select -Exp Name
Find the name of the Cruise Control service (CCService).$svcKey = Get-Item HKLM:\SYSTEM\CurrentControlSet\Services\$svcName
Grab the Registry key for the service.$newType = $svcKey.GetValue('Type') -bor 0x100
Get the Type value with the 9th bit set.Set-ItemProperty $svcKey.PSPath -Name Type -Value $newType
Set the Type value. The PowerShell Registry provider isn’t particularly intuitive here, IMO.- Fix for
git rm
during deleted/updated merge conflict - Branch expansion for
cherry-pick
,diff
,difftool
,log
andshow
- Normal expansion through simple aliases (e.g.
alias.dt = difftool
supportsgit dt <tab>
) - I’d still like to get some testing in place so I don’t break things unintentionally
- I’m considering moving away from regex to parse commands for tab expansion — anyone feel like writing a git command parser in PowerShell?
- I’d like it to be easier to use posh-git and posh-hg together, so I may revisit how they hook into tab expansion
Discovering Open Source: up-for-grabs.net
As open source gains more and more traction in the .NET space everywhere, a common question that keeps coming up is “How can I help?” To answer that question, a growing number of projects are tagging specific bugs and feature requests as good places for a new contributor to start. The tag to identify such tasks has not been standardized, but you should be able to figure it out…if you go and look.
To make discovering such projects easier, I’ve whipped together a site (page) hosted on GitHub: Up For Grabs. I’ve seeded the site with a few project links, but I hope over time we can grow this into a resource for newcomers to the open source scene to discover projects and get guidance on how to jump in!
Thanks to Scott for the nudge to get this started.
Update: Though the genesis of this site was a discussion on challenges facing the .NET open source community, I’ve come to realize that barriers to entry for new contributors exist across the entire open source ecosystem. So, if you run (or contribute to) any open source project that 1) has bugs and feature requests that you would consider “up for grabs” for new contributors, and 2) are interested in mentoring new contributors on their way to becoming great contributors, please add your project to the list.
Review: Instant Mercurial Distributed SCM Essentials How-to
I was recently offered a review copy of Instant Mercurial Distributed SCM Essentials How-to, presumably because I’m vocal about Mercurial being my backup DVCS of choice. Or something. So I worked my way through its 51 pages looking to fill in some gaps in my knowledge of Mercurial.
The Good
The book is arranged as a series of ten recipes along the natural path through learning a DVCS: installation, local workflow, remote workflow/collaboration, and some extras. The book also includes recipes on setting up mercurial-server, both using a file share and using SSH, and an introduction to Continuous Integration.
Though I was already familiar with DVCS concepts and Mercurial’s implementation, I did learn a few things:
Announcing posh-tf
As you may or may not know, I’ve been a fan of Git for a while now. I’ve hacked on an implementation of it, I’ve presented on it, I’ve even built a PowerShell environment for it that’s used by at least twelve people that aren’t related to me. Until a few months ago, I was content in my little Git bubble.
But recently I’ve been working with a team that has broadened my horizons and imparted a valuable lesson to me: “there’s nothing Git can do that TFS can’t.” Now if you’ve been following me for a while, you know this has been patently untrue. Until today.
Announcing posh-tf
Obviously the killer feature that TFS lacks as an alternative to Git is that it doesn’t integrate well with PowerShell. According to the UserVoice suggestion, at least one person thinks this needs to be remedied. And so I am pleased to present posh-tf: a PowerShell environment for Team Foundation.
posh-tf provides everything that posh-git provides, except for the things that aren’t readily available from tf.exe
:
Actually, it would probably be easier to just list what it does provide:
Can’t wait to get started? The readme has everything you need!
I’m thrilled with what I have to release today, and am looking forward to working with the TFS community to make posh-tf even better!
ASP.NET Web API List Parameter Binding
We chased our tails on this a bit today, so hopefully someone finds this useful.
The Problem
Your action needs to accept a list of primitives but your list parameter (of type T[]
, IEnumerable<T>
, List<T>
, etc) always comes back null
. You’re pretty sure an identical parameter has always work fine for an MVC action.
The Solution
Add [ModelBinder]
to the parameter:
public class ValuesController : ApiController { // GET api/values?id=Hello&id=%20world! public string Get([ModelBinder]List<string> id) { return string.Join(",", id); } }
Explanation
According to Mike Stall’s detailed post on Web API parameter binding, Web API only uses model binding for “simple types”, falling back on formatters for everything else. Adding [ModelBinder]
forces the complex types to use model binding anyway.
Related but not constructive: it feels weird naming a list parameter “id”, but even more weird using the API if it were named “ids”. Maybe just “x” instead?
posh-git v0.4
I figure a year between releases is plenty, so I’ve tagged a v0.4 release of posh-git.
Really the notion of versions for a bunch of scripts on which noone depends seems a bit silly…if a feature seems to be missing, get latest from master. If it’s still missing, send me a pull request (or log an issue). But I suppose it’s good to check in periodically to document what we’ve been up to.
New in this release:
Several others have contributed bug fixes as well—thanks everyone! It’s pretty awesome to work on something that someone else cares enough about to help improve.
If all goes according to plan, the next time you hear from me (about posh-git) will be to announce that migration to LibGit2Sharp is complete. I’m optimistic that the move will address the persistent performance concerns for large repositories. If you have a particularly troublesome repo, feel free to try my libgit2 branch and let me know if it’s better (or worse).
posh-git on Herding Code
Earlier this month I had the opportunity to record an episode of Herding Code with GitHubbers Paul Betts and Phil Haack on the state of Git for Windows: Herding Code 132. Topics included discussions on why Git hates developers and why Mercurial proponents’ claim that Git doesn’t preserve history is “nonsense.” I think the show turned out pretty well, and we got some hints as to what we can expect from GitHub for Windows. Thanks to the Herding Code guys for having us on!
Speaking of posh-git, there are a bunch of new goodies in my master branch including tab expansion for remote branches, support for the Nuget console, and easier integration with posh-hg. I’ll post more details with the upcoming v0.4 release.
Los Techies at CodeMash 2.0.1.2
Every January a swarm of geeks descend on the Kalahari Resort in Sandusky, OH for CodeMash, a top-notch cross-platform, family-friendly developer conference. This year’s event features an impressive session list including presentations by Scott Hanselman, Jon Skeet, Glenn Block of CodeBetter, Rob Reynolds of Devlicious…the list goes on. And that’s just in the .NET track! Also on that list you’ll find three sessions featuring members of Los Techies:
I had a great time at CodeMash last year, and this year is shaping up to be even better. Registration opens today (Oct. 24) at 10:24 AM EDT and you’ll want to reserve your spot soon—last year’s event sold out in less than four days!
If you do make it to the event, please ping me on Twitter so we can meet up!
Git Beyond the D in DVCS
Jimmy’s post is a nice reminder of the advantages of a distributed version control system. But having ramped up on Git primarily through git-svn, I thought it would be worth enumerating some of the advantages I’ve found just in my local workflow:
1. Local Branching
More than anything, cheap local branches have changed how I work. I don’t know any developers that have the luxury of only working on one thing at a time. Not only do local branches provide the perfect mechanism to compartmentalize work on different features (or just ideas you’d like to try), but Git’s branching mechanism also works great for trying different approaches to the same problem. It’s trivial to reset a branch back a few commits if an idea doesn’t work out, or create a new branch from a few commits ago to see if there’s a better way.
The other advantage of local branches is that they’re not public unless you want them to be. Not only are centralized branches slower to work with and commit to, the ceremony required to set them (if you have permission at all) attaches a feeling of permanence—I’m less likely to commit something that’s not necessarily finished, but may still be useful. I don’t have these reservations with Git—my main repository at work has maybe 20 branches of refactorings, spikes and other works in progress that I’m free to revisit as time allows without feeling self-conscious about their current lack of polish.
2. Smarter Merging
Because of Git’s focus on file content rather than file location, it’s much better at resolving merge conflicts for you, especially across renames. That’s not to say you’ll never get conflicts, but they’re typically real conflicts—files deleted in one branch and modified in another, overlapping Visual Studio project file changes, etc. And for those you can hook up a 3-way merge tool like Beyond Compare or P4Merge to make quick work of them.
3. Pause and Resume
So your boss comes in and says something to the effect of “stop everything you’re doing and make this change for the CEO.” What do you do? In SVN you might create a patch file of your work in progress and revert. In TFS you might shelve your changes up to the server. In Git you have a two options that are built right in:
The disadvantage of stashes is that they’re not explicitly tied to the branch where the work happened. The longer it takes to get back to what you were working on, the higher the chance you’ll forget you had some work stashed.</li>
* Stage all your changes and make a temporary commit that you’ll later revert:
<pre>$ git add -A && git commit -m "I love interruptions!" $ git checkout master -b pti # ... save the day ... $ git checkout my-feature $ git reset HEAD~</pre>
The kicker is the final command, which moves the `my-feature` branch pointer back one (to `HEAD`‘s parent) but leaves the working directory unchanged—keeping your old work in progress. The advantage of this approach is that the temporary commit lives with the branch where the changes belong.</li> </ol>
It doesn’t take long for both of these operations to become second-nature, greatly decreasing the impact of these interruptions.
## 4. Rewriting History
Pretending a temporary commit never happened is just one example of rewriting history, which becomes a fundamental operation for an intermediate/advanced Git user. But first, our cardinal rule:
<p style="padding-left: 30px;">
<strong>Once a commit is pushed, it’s permanent.</strong>
</p>
History that has been shared with others is off-limits for rewriting unless you have explicitly communicated that history may be rewritten. For example, I routinely overwrite branches I push based on pull request feedback, but once something hits [posh-git](https://github.com/dahlbyk/posh-git)‘s master branch it’s there for good.
So with that out of the way, I present my corollary to the cardinal rule:
<p style="padding-left: 30px;">
<strong>Until you push, pretend you’re perfect.</strong>
</p>
In the simplest case, this might simply mean using `git commit --amend` to fix a typo in the last commit’s message, or include changes to a file that you forgot to save. For more complex needs, like pretending you wrote your tests _before_ the implementation, check out the amazing [interactive rebase](http://book.git-scm.com/4_interactive_rebasing.html).
## 5. The Staging Area
Some people view Git’s staging area as an annoyance—an extra step between code and commit. I simply see it as your standard commit dialog with all the boxes unchecked by default. Checking all the boxes is as simple as `git add -A`, which I alias as `git aa` (`git config --global alias.aa "add -A"`). Or you can use `git commit -a` to stage all changes before commiting (though this won’t pick up additions or deletions).
The real power, though, comes from the ability to stage (`git add --patch`) and unstage (`git reset --patch`) parts of your changes before commiting. You can even use `git checkout --patch` to revert some changes in your working directory without affecting others, or even to pull in partial changes from another commit altogether.
I use this feature on an almost daily basis to separate cosmetic changes from refactoring from new feature work, without having to undo some changes so that I can commit the others. The result is more smaller, atomic commits that separate inert changes from those that actually change behavior.
## Tip of the Iceberg
Ultimately these are just a few of the things that have convinced me Git is worth the learning curve, worth the cost to migrate, worth the cost to retrain your staff; and this doesn’t even touch on the advantages and flexibility of Git’s distributed nature. I just hope to pique your interest enough that you give it a try for yourself.
And if you’re already using Git, how does this compare with your list of must-have features?
Allowing a Windows Service to Interact with Desktop without LocalSystem
One of the biggest roadblocks with getting automated browser tests (we use WatiN) running in a Windows Continuous Integration environment is figuring out how to let the build server interact with the desktop. Typically there have been two options:
[<img title="Allow service to interact with desktop" src="/content/keithdahlby/uploads/2011/08/AllowServiceToInteractWithDesktop.png" alt=""Allow service to interact with desktop" in Windows Service Properties" width="410" height="461" />](/content/keithdahlby/uploads/2011/08/AllowServiceToInteractWithDesktop.png)
A third option now is to run the build service as a user of your choice and set “Allow service to interact with desktop” through the Windows Registry. A Code Project article identified the necessary Registry setting, but still suggested the account must be LocalSystem. However, the same setting appears to work for other accounts as well. I’ve put together a simple PowerShell script to make the change; just run it with administrative privileges:
If you’re not a PowerShell person:
posh-git Release v0.3
On a whim, I’ve decided to tag a v0.3 release of posh-git (which has been stable for a few months now). In this release…
Installer
Previously the setup process for posh-git was undefined. Daniel Hoelbling was kind enough to put together a getting-started post, but I decided to make it even easier. Assuming Git and PowerShell are configured correctly (see readme for details), getting started is trivial:
cd C:\Wherever git clone https://github.com/dahlbyk/posh-git.git .\posh-git\install.ps1
At this point the sample posh-git profile will be loaded as part of your PowerShell profile. If you don’t like the sample profile, feel free to grab the pieces you want and discard the rest (so you can use posh-hg too, perhaps).
** If you already have posh-git installed, just cd
into your posh-git directory and pull from my master
branch:
# If you don't already have me as a remote... git remote add dahlbyk git pull --rebase dahlbyk master
You don’t need to run install.ps1
again; just open a new PowerShell session and you’re good to go.
Performance
By taking a dependency on msysgit 1.7.1, all status information is now retrieved in a single call (git status -s -b
). This still means git status
is called for every prompt, so if status
is slow for your repository your prompt will be slow too.
If it’s still too slow for your taste, you also have the option to set $GitPromptSettings.EnableFileStatus = $false
. This will preserve branch information for the prompt, but skip everything else (counts and tab completion for added/modified/deleted files).
Finally, you can set $GitPromptSettings.Debug = $true
to see how long the various steps take behind the scenes. If your environment is anything like mine, the majority of the time will be spent in git
calls.
Tab Expansion Updates
Next Steps
As always, your feedback is appreciated. If you’d like posh-git updates between release posts, you can also follow me on Twitter.
subscribe via RSS