dahlbyk / posh-git

A PowerShell environment for Git
http://dahlbyk.github.io/posh-git/
MIT License
7.62k stars 799 forks source link

Create core git commands as PowerShell cmdlets #97

Closed powercode closed 7 years ago

powercode commented 11 years ago

Hi all,

I would like to see posh-git move into a more full fledged PowerShell citizen. One of the hall marks of that would be cmdlets outputting objects for the core functionality.

My initial suggestions would be Get-GitLog Get-GitStatus and for bonus points, just to show the power of PowerShell, Convert-GitBranch (for git filter-branch)

Convert-GitBranch -Branch master -Begin{ $NameTable = @{} ... code to fill $NameTable } -Process { param([Commit] $Commit)
$Commit.Author.Name = $NameTable[$Commit.Author.Name] }

I'd be glad to chip in on this on. I'm a git/github newbie, but experienced with PowerShell, both as a user/scripter and as a cmdlet developer.

Is libgit2sharp mature enough to be able to do this?

dahlbyk commented 11 years ago

It's funny you mention this...I've been working on a blog post that essentially proposes exactly this (in my head I'm calling this new set of functionality "posh-git 2.0" even though I've not actually tagged 1.0).

My tentative long-term goal is to make posh-git's dependency on msysGit optional. I think we can pull that off with a combination of proper PowerShell cmdlets (as you propose) and a smart git function that understands its native operations but leverages PowerShell when possible. I think this would be a "best of both worlds" kind of implementation (accessible to experienced users, more discoverable to PowerShell users).

I'm a git/github newbie, but experienced with PowerShell, both as a user/scripter and as a cmdlet developer.

As you can surely tell, I'm basically the opposite so any input would be appreciated.

Is libgit2sharp mature enough to be able to do this?

In some places, yes; in other places, no. It's definitely mature enough to start working in this direction.

Two initial questions:

  1. Would it be better to develop cmdlets in C# or PowerShell?
  2. How can we test the new functionality? Not having tests for what's included so far makes me quite sad.
powercode commented 11 years ago

Would it be better to develop cmdlets in C# or PowerShell?

If we are using libgit2sharp, it will probably be easier to do it in C#. The good thing is that we can pick an choose, cmdlet by cmdlet. By using a module manifest, we can start implementing stuff in PowerShell, and later move it to C# or vice versa. One issue we have to consider is that some objects from libgit2sharp has lifespan connected to their repository. We may have to create new objects of a different type with copies of the relevant data to let them live as long as necessary in PowerShell. (Maybe this is me not understanding libgit2sharp. I ran into the issue while toying with it)

How can we test the new functionality? Not having tests for what's included so far makes me quite sad.

I guess our best option is to compare the object output to manually translated output from sample repos. I.E generating the "correct answer" with the native commands, and use standard unit tests to ensure that the output from the cmdlets is correct.

Usually, the best way is to have plain old C# functions doing all the heavy lifting, and the Cmdlet as thin wrappers around the functions. The cmdlets are only responsible for parameter parsing, progress and output.

wekempf commented 11 years ago

Funny, I prefer pure PowerShell modules :). Using C# just complicates things, requiring a build process and all. But I get the argument for using C#. As for testing, if you use C# you mostly just need standard unit tests. However, there are unit testing frameworks for PowerShell, such as PsUnit and Pester. I've actually been working on one of my own, not being totally fond of either of those, but the point is it is possible to write tests for PowerShell.

powercode commented 11 years ago

I have another reason for preferring C#, and that is speed. I want to make posh-git a best-of-breed git front end, and when working with large data sets, writing cmdlets in C# really does give them an edge. But I'm not religious about it.

There is another thing that is a bit nicer when using native code, and that is how the OutputType attribute works. There are workarounds to make it somewhat OK, and you can do hybrid solutions, with data types defined in a C# dll, and referenced/used from PowerShell scripts.

When cmdlets gets bigger/more complicated, I have found it valuable to have the support of a type system and better IDE's.

For those who are new to the OutputType, it is a way for cmdlets to tell the PowerShell host what kind of objects they output, to give tab completion data to downstream objects. It makes for an excellent experience when for example typing

Get-GitLog | foreach < Tab >

mgohmann commented 11 years ago

Hi all, I have been thinking about something similar. I've got some experience with PowerShell, but not much with Git. Was thinking of something along the lines of on an "add-on" for PoSh-Git with the target audience being PowerShell people. Wrapping Git commands in PowerShell style cmdlets. I've got some notes on my home computer which I will post this evening.

One of the ideas that might have value is anytime you run a cmdlet it also shows the actual Git command. So people comfortable with PowerShell will learn Git along the way.

bdukes commented 11 years ago

I'm definitely in favor of having cmdlets which will give structured data out, to give something better than text searching to get answers to questions.

JayBazuzi commented 11 years ago

I love PowerShell's consistent, powerful, flexible, easy-to-use parameter processing. I love passing objects in pipelines. I'm so bummed that it's Windows-only (which is why I'm writing Pash).

I love GIT's distributed VCS -- the forking, the branching, the merging. Its UI is horrible. Why are there 3 names for index/cache/stage? Why do git checkout -b FOO and git checkout . mean such very different things, while git checkout . is very similar to git reset --hard?

I like the way GitHub lets us come together, share, fork, collaborate.

If you write rich cmdlets for GIT, will you keep the same basic interface, but with PowerShell terminology? Will there be a cmdlet that does both of the functions of git checkout? If yes, you are recreating something stupid, which is an unnatural fit for PowerShell. If no, you're obsolescing tons of existing GIT expertise.

Do you think you'll reach complete parity with GIT? "yes" is very hard to reach, especially if you design a new interface to GIT that is PowerShell idiomatic. "no" means everyone will need to know both posh-git and GIT to get their work done.

These aren't new problems - GitHub for Windows deals with many of them, with mixed results.

bdukes commented 11 years ago

@JayBazuzi I would think that there wouldn't be complete parity, but start with the most common commands, and add more as time allows and needs are demonstrated.

In terms of the commands, I would expect that there would be friendly commands (e.g. New-GitBranch cats); there might also be commands that are closer to the original git commands, too, but I'm not sure how that fits into the git verb naming convention... Checkout-GitRef -NewBranch cats perhaps? Is there an existing posh verb that would fit existing multi-purpose commands?

dahlbyk commented 11 years ago

@JayBazuzi you make excellent points. The transition between Git proper and an idiomatic posh-git dialect could be challenging, but I think we could get to the point where you can largely pick one and stick with it.

Will there be a cmdlet that does both of the functions of git checkout? If yes, you are recreating something stupid, which is an unnatural fit for PowerShell. If no, you're obsolescing tons of existing GIT expertise.

I'd like to avoid recreating "something stupid" and unnatural, while also not obsoleting existing Git knowledge. Suppose we build with a set of more natural cmdlets (e.g. checkout becomes Switch-GitBranch -Ref ..., Update-GitItem -Path ... -Ref ..., maybe the -b option becomes a -Switch flag on New-GitBranch?), but then teach a git wrapper function to inspect the checkout command and figure out which PowerShell cmdlet would be equivalent).

Realistically we won't know how some of this shakes out until we try. I've wanted to for a while, but it's good to hear I'm not alone.

powercode commented 11 years ago

@JayBazuzi I don't think we should have complete parity as a goal. Git power users will use git for more specialized tasks, and I think we should aim at something that feels consistent and familiar for the PowerShell community. That means that we should use the standard verbs, even when at odds with the name of the git commands, but maybe add a mapping section in the module help describing the mappings, for example

git pull => Sync-GitItem(/Branch/Repository) git filter-branch => Convert-SvnBranch

We should aim at having each command perform one clear task, and not use the swiss army knife style of git.

The PowerShell verb for making a resource available to someone else is Publish so git push would not map to Push-GitBranch but to Publish-GitBranch. I'm sure this will lead to some controversies =)

There is a good list of PowerShell verbs on http://msdn.microsoft.com/en-us/library/windows/desktop/ms714428(v=vs.85).aspx, with descriptions of them. I think a good way to approach this is to look at the benefit of having a certain command as a cmdlet instead of using the git original.

Discoverability may be one of the things. Being able to do the most common operations is another, and finally, I think we should have a go at the things where the git-powershell impedance mismatch is the greatest. That is in my view for example where I have to write shell scripts to accomplish a task, such as filter-branch.

I'm would need to be convinced that we should for example add a New-GitBranch -Switch parameter. I think that the more powershelly way would be to let New-GitBranch emit an object with a Branch Property, that could be piped to Switch-GitBranch.

New-GitBranch dogs | Switch-GitBranch ngb dogs | swgb

And if someone things that is to much typing, they can always create a custom function to wrap that in a Proxy Function (http://blogs.msdn.com/b/powershell/archive/2009/01/04/extending-and-or-modifing-commands-with-proxies.aspx) adding the switch or an ordinary function used as their shortcut.

powercode commented 11 years ago

I would love if some git experts could chip in with how the core git commands should map to the approved PowerShell verbs.

And how do we handle things like rebase, fetch pull, merge?

Sync has the description "Assures that two or more resources are in the same state." Update has "Brings a resource up-to-date to maintain its state, accuracy, conformance, or compliance." Merge has "Creates a single resource from multiple resources."

Should we start with a prioritized list of the core git operations that we want to implement, and then decide on the naming and design of the cmdlets?

I put something out to start working with

Git command PowerShell cmdlets PowerShell alias
git log Get-GitLog ggl
git status Get-GitStatus ggs
git init New-GitRepository ngr
git clone Copy-GitRepository cpgi
git branch (-a) Get-GitBranch ggb
git checkout Switch-GitBranch, , New-GitBranch swgb,ngb
git add Add-GitItem agi
git commit Submit-GitItem sbgi
git merge Merge-GitBranch mggb
git filter-branch Set-GitItem?? sgi
git reset Reset-GitItem rsgi
git rm Remove-GitItem rmgi
git mv Move-GitItem mvgi
git push Publish-GitItem pbgi

Is this a good set of commands to start with?

bdukes commented 11 years ago

I like those suggestions in general. I would think of git push as Publish-GitBranch, rather than Item (and same with commit/Submit). Similarly, would we want Reset-GitItem and Reset-GitBranch, or one command that can act on individual files and the whole thing?

bdukes commented 11 years ago

Some other commands which would be used a lot:

GitPowerShellalias
git configGet-GitConfigurationggc
git configSet-GitConfigurationsgc
git diff[tool]Get-GitDiff or Compare-GitBranchggd or crgb
git stashPush-GitStash or Checkpoint-GitBranchpu-stash or chgb
git stash apply/popPop-GitStash or Restore-GitBranchpgs or rrgb
git tagNew-GitTagngt
git tagGet-GitTagggt
git fetchRead-GitRemoterdgr
git pullReceive-GitRemotercgr
git remote addNew-GitRemotengr
git remoteGet-GitRemoveggr

The rest of the commands, in order of how likely I'd use them :-)

  1. rebase
  2. cherry-pick
  3. format-patch
  4. bisect
  5. blame
  6. submodule
  7. gc
  8. show *
  9. shortlog *
  10. describe *
  11. reflog
  12. am
  13. apply
  14. send-email
  15. request-pull
  16. svn
  17. fast-import
  18. clean
  19. fsck
  20. instaweb
  21. archive
  22. daemon
  23. update-server-info
    • perhaps these are implied by other Get- cmdlets above?
JayBazuzi commented 11 years ago

My impression reading this thread is that most of the focus is on creating PowerShell cmdlets that are convenient to use interactively at the command prompt. The value delivered would be a sane syntax with PowerShell's rich, consistent parameter handling and TAB completion. If that's your goal, you'll probably end up with 1, 2, or 3 cmdlets for each GIT command, as you tease apart the distinct functions of those commands.

A different approach would be to focus on taking advantage of PowerShell's object streaming, so you can write things like:

Get-GitLog | ? { $_.Author -ne $_.Committer } | Select Author,Committer,sha1

On Linux, people use awk/sed/grep to do these kinds of operations, and I'm so glad to get away from that with PowerShell.

If you took this approach, you would focus on query commands.

bdukes commented 11 years ago

I do agree that queries make sense to implement first, teasing the output into something that can be filtered and displayed however you want.

dahlbyk commented 11 years ago

I think we need both. The challenge for commands is coming up with idiomatic naming that's discoverable and memorable. The challenge for query cmdlets is deciding what to expose, and how to do so with good performance - in general, handling this idiomatically seems less challenging.

jstangroome commented 11 years ago

I wouldn't be concerned about performance as a reason for choosing C# vs PowerShell for implementing the cmdlets until you've measured the performance and found a need to optimise.

If you need several cmdlets to share common parameters using C# will help by allowing you to introduce a base cmdlet class with these parameters. Implementing this in PowerShell will involve copy and paste - not immediately bad but worth considering.

Ideally, any PowerShell cmdlets for git should, via Write-Verbose, output the original git.exe equivalent command syntax so that users can more easily swap between the two.

AndySchneiderDev-zz commented 11 years ago

I am really excited about the direction this is going, and would love to help out as well. I am a PS geek but pretty new to GIT. As far as using C# vs PowerShell script, you'd probably get more people able to help/debug PS scripts rather than C# purely from a skill set perspective. A lot of PowerShell scripters don't have VS and are not familiar with C#, and I would think Script writers would be a good chunk of the users for the Cmdlets.

dahlbyk commented 11 years ago

I'm fine going either direction, really. My only hard requirement is that we have tests. And even if the implementation is in C# with some normal unit tests, it would be good to have a suite of PowerShell tests to document and verify expected behavior (chainability of calls, etc).

AndySchneiderDev-zz commented 11 years ago

I am at the PowerShell Summit this week and just went to a talk on Pester... which lets you do unit testing for PowerShell. Might be a possibility. https://github.com/pester/Pester

JayBazuzi commented 11 years ago

My only hard requirement is that we have tests.

Interesting: that is basically the same conclusion I came to for Pash. I have a lot of ideas about what I think is good code, but for a community-run, volunteer-only, open source project, it seems that tests are the natural conclusion for the question of "what do I absolutely require before I accept your pull request?"

klumsy commented 10 years ago

I'm thinking of doing something like this, however my goal isn't either to not have git installed/ nor to have a nice powershell syntax covering most common git operations, or even make a git PS provider. I think for the most part, like the syntax or not, git syntax is set in stone, and here to stay. I want to basically use libgit2sharp as a way to make commands that deal with Git in a object and data centric way. So mostly probably for statistics and reporting and first, and nothing that makes changes. However there are probably a lot of good scenarios where the data pipeline would be useful for things we do in git.. get-x | filter-something | do-y sort of thing, and i'd probably like to start covering those too.

omidkrad commented 10 years ago

This is still an outstanding topic and better PowerShell support for git (object outputs) is really needed. I saw @staffang's PSGit project which is a good start; I hope you guys plan on continuing this effort, and hopefully see it integrated with POSH.

NiloCK commented 9 years ago

This is an old issue which I'm sure people still have interest in. I'm fairly new to both powershell and git so forgive me if I'm off base with this.

My own take on this issue is that it's more immediately useful, and perhaps a gentler starting point to get the ball rolling, to override the regular git commands such that they return sensible objects/collections for the pipe.

Eg: `git status | gm' currently reports that the passed object is a string, namely the output that's printed when the command is run, whereas ideally a collection of StatusEntry objects would be coming across.

The benefit here is that it can be introduced piecewise with no usability hurdles on existing git / posh-git users, and little need for consensus building with respect to naming convention, coverage, etc.

Jaykul commented 9 years ago

Hey, if anyone is still paying attention here, a couple of us are playing around with trying to actually write this, and I'd like some feedback on a design question: PoshCode/PSGit#10

dahlbyk commented 7 years ago

Closing in deference to PSGit