Hacker News new | past | comments | ask | show | jobs | submit login
Git 2.0 release notes (kernel.org)
230 points by redox_ on Mar 12, 2014 | hide | past | web | favorite | 90 comments

I like a lot of these things for sure. The only thing that I really wish they'd do that I've seen no sign they plan to is move git-subtree from contrib into the main distribution. It's such a useful thing.

I agree! Overall I truly prefer git subtree over submodules. I've noticed that most devs seem to have strong opinions one way or another.

Perhaps git subtree just seems so good because submodules are so clunky. If only someone would invent a "best of both worlds".

>I've noticed that most devs seem to have strong opinions one way or another.

I've personally noticed that most devs don't have an opinion either way since they don't use subtrees nor submodules.

I don't know what subtrees offer but using submodules has been very pleasant once you know how they work. For example if you version control your .vim I think that adding submodules for extensions is way better than cloning them inside your .vim.

I look forward to having the opportunity to use subtrees.

Subtrees interact with history in a much more obvious, configurable, and automatic way. The most obvious win is never having to run `git submodule update`. The better control over history is the bigger, but less obvious win. Since you have some experience using submodules for your .vim, maybe try switching to subtrees and see what you think. I like the Atlassian blog post[0] about them for getting started.

[0]: http://blogs.atlassian.com/2013/05/alternatives-to-git-submo...

For me the the most obvious win is still being able to merge, move forward in time, move backward in time, rebase, etc. Everything that makes Git great.

Once you have submodules in your repo, all that becomes heinous. PLUS everything you mentioned...

Sure, if you don't use those features, then submodules would probably work fine. But then why not just use Dropbox?

Yep, I think a good way to put it is that subtrees are (or feel like) far more "first class" - you can do all the normal stuff with them.

And then you try to bisect on a repository using submodules and you tear your goddamn hair out.

I used to do this for my .emacs files and modules. It worked quite well, but in the end package.el made it unnecessary. Since then I came to the conclusion that git submodules are not a real substitute for a package manager.

And for vim vundle makes this unecessary.


Any chance you could outline the downside of subtree? I've always thought it was better in every way.

Submodule can be used when you want to nest a private repository inside of a public one. Only authorized users will be able to fetch from the submodule repository. This can be useful in some cases, such as storing private keys in an otherwise public project.

Also, if you have a very large submodule repository, it won't inflate the size of the repository that contains it.

git-subtree can flatten the other tree into a single commit while preserving the ability to use all its other functionality, which is actually probably a space-saving measure compared to submodules when you consider that anyone who uses your repo probably needs to get the submodule anyway, and that means downloading that other giant repo in its entirety vs. downloading a flattened copy of it.

So if I understand this correctly, it is more of a convenient way to copy (and update) another repository into another one, instead of being a reference to another repository.

To respond to the comment about this being useful for private keys: if this is the case, does this also mean unauthorized users will not be able to checkout the submodule at all? Or will they just get a copy of the files (which would not make sense with private keys).

When you git clone a repository with a submodule, before you call git submodule sync/update and all that jazz, you just have an empty directory where the submodule should be.

Subtree operations modify commits (and trees). As a result, cryptographically signing or validating a subtree operation does not extend to an independent module, and vice versa. If you care about these things, it's a big deal.

If you use git-subtree in the mode that doesn't flatten the original tree it does not, afaik, modify any commits on either side. The original tree, as imported, and the tree being imported to, are both parents of the post-subtree tree with their original SHAs.

Wasn't aware of that. That's kind of awesome.

You seem to be very knowledgeable about subtree, so I'll ask a question you can hopefully answer:

I have multiple repositories each having 100,000-500,000 files, all relating to the same project. The reason I broke them up to multiple projects is that the git index doesn't handle millions of files all that well (e.g. index gets rewritten on every modification). Would subtree help me here in any way?

Of course, this is not a usual way to use git, and Facebook opted for switching to Mercurial when faced with a similar problem (though an order of magnitude or two larger, I'm sure).

submodules work for me now, but they are very clunky -- but the reason I didn't even try switching was the crypto signing of commits, which is apparently not a problem. Would subtrees help me with the scale as well in any way?

No, I don't think subtrees can really help you with this unfortunately. At least not directly. Using the flattened mode might help, but then you'd be back to your problem with signing them. The subtree merge commit does record the original SHA, so I suppose you could verify as a separate step if you needed to that that merge commit is indeed the result of a correctly signed SHA somehow.

But I think for your use case you're probably stuck with submodules.

You may want to take a look at https://github.com/ingydotnet/git-subrepo#readme (and join #git-commands on freenode).

Wow, from glancing at the description it sounds really good. I hope you guys can pull it off! Something like this would be almost as "freeing" to me as starting to use git in the first place was.

how close is git-subtree to svn-externals? I've always had people complain about moving from svn to git because there wasn't a feature like svn-externals. git-submodules obviously didn't cut it.

It's kind of difficult to compare. I actually think of submodules as being much closer to svn externals in nature, just very poorly integrated (I'm not sure anyone on the git core team actually uses submodules, in things I've read as justification for its poor implementation from core team members it seems like they only added it as a checkbox feature).

Subtrees are quite different from either. They make the imported repository literally a part of the commit graph of the parent tree through a subtree-merge-commit. It then does some extra work to help you bring in new changes or export new changes back.

I think it's a better approach than either, but it's also not exactly the same thing, basically.

In my opinion it's way better then submodule or svn-externals. Basically it allows you to take an specific folder from your repository and push only this folder to an additional repository. This repository could be included into another repository which makes sharing code between repositories very easy while keeping history in each of them and the history for this special folder in an extra repository.

Is there any intention among the Git developers to ever make --recursive a default option for git clone? (This is an option that causes git clone to recursively clone any submodules as well as the top-level repo.)

Sure, arguably there are fundamental issues with submodules that you won't ever solve, and some people might prefer subtree to become the default. (I won't get into that argument here as there is another thread addressing that topic.)

But the fact still stands that a lot of the ugliness of submodules comes from the fact that the UI forces users to learn a whole extra set of commands, while the regular commands are largely oblivious to the existence of submodule. If I make a Git repo with submodules, I can't just pass a link to my Git-novice friends and have them clone it, because the UI for submodules is separate from the main Git UI. Arguably, for users who don't need to actually touch the submodule, the fact that the submodule is there should be invisible from the perspective of the UI. Although Git has been gradually getting closer to this being true, it is not currently the case (clone being an example of one command which is not aware of submodules by default).

Is it just me or "simple semantics" is not at all simple? Compare with:

    hg push -- pushes everything to "default push location"
    hg push -r . -- pushes currently checked out branch
    hg push -r foo where -- pushes foo to where

> Is it just me or "simple semantics" is not at all simple?

It's just you.

It's about time we'd put "hg vs. git" to the category of flamebait topics (similar to "emacs vs. vi" etc) that should be avoided. Every time there's a git topic, someone comes and derails the whole discussion with a not-quite-apt comparison with hg.

AFAIK, there are decent two-way conversion tools so you can use hg with a git repo and vice versa. There should be no need to argue because you can pick the one you like and use it.

So comparing two competing tools is flamebait nowadays?

I think the OP makes a valid and argumented point.

I would agree with you if there had been an actual comparison and some arguments for or against one or the other. Now there wasn't.

E.g. "git push", similarly to "hg push" - without any extra arguments - do roughly the same thing, "push to the default location".

When was the last time you ever saw anything useful or insightful in comments about git vs. hg? There have been a few enlightening blog posts on the subject but discussion threads like this don't really provide anything of value.

> ...if there had been an actual comparison and some arguments for or against one or the other.

What kind of comparison are you after?

To be more scientific, let's take "git push where" and "hg push where". Now count the number of ifs and buts that you have to keep in mind when using Git (am I pushing to the same remote? is the branch "set to integrate"? does the remote has this branch name?) versus plain "push everything to where you cloned from" in Mercurial.

My point is that Git has accumulated too much cruft and has introduced one too many concepts to be usable.

My point is that Git has accumulated too much cruft and has introduced one too many concepts to be usable.

Your point is totally invalid, since git is self-evidently successful, and regarded by many people as usable.

The "cruft" you've pointed to consists of usable, useful features. So it would be useful to talk more about areas in which git could improve—even if that involves looking at features from Mercurial—rather than engaging in vague and abstract descriptions of "cruft".

As much as you want IT world to be a meritocracy, it is not. Very rarely software gets popular based exclusively on its merits.

With Git, it gained popularity not because it was terribly usable [1] or generally good (it was not even going to be an SCM [2]), but because it was imposed by Linus onto a pretty large number of developers - kernel hackers, not less - and then it spread from there.

[1]: http://marc.info/?l=git&m=111377572329534 [2]: http://marc.info/?l=linux-kernel&m=111288700902396

I'm familiar with the history of git.

I'm also aware that nothing you said actually dealt with the fact that git is not unusable. In fact, it's objectively pretty good—if it weren't, we'd all still be using SVN.

What you seem to be saying is that you prefer the UX of Mercurial. Cool, that's fine - but I'd be keen for people to invest their time in improving the experience of using git, rather than bellyaching about perceived differences which aren't really all that big.

(As an aside, I don't really agree that there's a problem with git's usability. It's a complex tool, if you want it to be. But for day-to-day distributed SCM, you'll rarely have to care about most of that.)

There are no objective criteria to measure usability, so Git cannot possibly be "objectively pretty good", sorry.

Again, popularity has nothing to do with merit. It's a pure happenstance that Git was chosen over Mercurial for kernel development, and it all went from there.

The UX of Git cannot possibly be improved in the foreseeable future as it will be a _massive_ pile of breaking changes with people moaning all over the internet.

Git is not as bad as you claim, and Hg is not as good as you claim. Yes, I have used both.

If you're looking to derail this post and do some trolling, then congratulations. You're off to a great start.


Git push by default pushes to where you cloned from. If you want to push to a different remote, you say so: "git push another-remote". If the remote doesn't have that branch, you create it, same as you would with bookmarks in mercurial.

git push == push all branches to origin hg push == push all changesets to origin

It is if there was no new development in the tools and/or the comparison just repeats what has been said thousands of times already.

This (root) comment here is a good example: it isn't in any way related to the new developments in Git, repeats very basic comparison done many times already and fails to account for deeper differences and options (like the fact that you can easily configure git to make git push do exactly what you want).

It would be good for overall discussion quality if posts such as these were kept separate from the interesting stuff.

Also, hasn't git won already? I mean, I'm sure Mercurial is a great tool and all, but git is massive and widespread now, there's no going back and sharing of the pie until a new generation of VCS that completely changes the game emerges I think.

When you say "the currently checked out branch", do you mean the current branch, bookmark, head, local branch or mutable branch? Or maybe you are referring to the current phase, or a secret changeset?

"Mercurial is so much simpler than git" is only true for one reason: You prefer mercurial and dislike git, and so you look for flaws in git while glossing over flaws in mercurial.

You just need to visualize the tree, and that's it. `hg push -r .` will push checked out changeset and all its ancestors.

Mercurial tracks changesets. Git guys are inventing all kings of weird entities. Local branch? Mutable branch? Do these kind of things have separate sets of semantics in the git world?

In mercurial, branch is just a constant name for a group of changesets. Bookmark is just a temporary pointer to the changeset. Head is a changeset (that have no successors). Phase is information about whether it is safe to modify changeset. Mercurial is indeed a lot simpler.

I think you misunderstood. These "weird entities" that I mention are all part of mercurial. I feel like many of the people who complain that git is too complicated and hold up mercurial as a bastion of simplicity don't really know either of them.

To quote my other comment:

* Branches (named and unnamed) are part of core mercurial.

* Bookmarks are part of core mercurial.

* Multiple heads are part of core mercurial.

* Phases are part of core mercurial.

* Secret changesets is part of core mercurial.

* mq is distributed with Mercurial.

* Local branches is an extension that isn't part of core mercurial, I'll give you that. However, calling it a "third-party extension" is pedantic. It's listed on the official mercurial web site, and using extensions is much more a part of every day usage of mercurial than using extensions in git, for example.

All branches can change, and are mutable in that regard (altough commits can't change).

Local branch == Bookmark with unpushed changesets

All branches and commits/changesets are treated equal.

Yeah. In mercurial you have Branches and Bookmarks. In git you just have branches. Head is the current checked out commit/changeset. Git doesn't allow you to alter commits, only branches, so every modification in Git is inherently safe.

Also, mercurial has mq, which adds a whole extra layer of complexity. Instead of making safe commits, you continually update ("refresh") a set of patch files. Each time you refresh you lose all the history (as if you exclusively used git commit --amend for work in progress). In order to solve this someone got the idea that the patch queue itself could be versioned by creating a second repository that you would commit each revision of the patches to. Unsurprisingly it turns out that two repos are not better than one and doing "simple" things (moving a patch queue between two clones of the same remote) requires fiddly manual operations.

Mercurial has some neat features, but this idea that it's always easy to use and git is always hard to use simply isn't true.

To be fair, mq is needed only for very few specialised needs (apart from strip, maybe). Most hg users can get by just fine with never enabling it at all.

For years the Hg community proclaimed it was the answer to git rebase. Might be time for a concerted doc push to get those references updated with pointers to the rebase extension instead.

Because it was the answer originally (it's wiki page appeared in 2005, rebase appeared in 2008). Then rebase became the better answer. What proclaimed answer are you referring to here? On their GitConcepts[0] page, it says "hg rebase" or "hg histedit" should be used to do "git rebase" type operations. The only time they recommend MQ is if you want the index or the "git am" type command.

And as anton_gogolev mentioned, ChangesetEvolution[1] will probably help augment HistEdit and Rebase for a number of operations. It will allow pushable history rewriting.

[0] http://mercurial.selenic.com/wiki/GitConcepts

[1] http://mercurial.selenic.com/wiki/ChangesetEvolution

> What proclaimed answer are you referring to here?

You answered that in your first paragraph: for many years, the first time people looked at Mercurial the answer for that class of problems was mq. The problem now is that it's still easy to find stale internal documentation, old blog posts, etc. which haven't been updated with the new recommendations. I thought that it might be worth having a small campaign to encourage people to update old wikis, contact blog authors, etc. when they find those recommendations and suggest a simple “this is no longer recommended – see …” update.

Answer to rebase in particular (and the whole "Git makes it simple to edit history" argument in general) is Changeset Evolution [1].

[1]: https://air.mozilla.org/changesets-evolution-with-mercurial/

> In mercurial you have Branches and Bookmarks. In git you just have branches.

I think git branches correspond more to hg bookmarks, than to hg named branches.

Isn't the only real difference that hg branches are constant, while bookmarks are temporary?

Yeah, in hg named branches the branch name is forever logged as part of the commit. Hg bookmarks and git branches are just pointers to the most recent commit.

http://jordi.inversethought.com/blog/on-gitology/ is a good explanation of how git is overly complex.

Or maybe it is Git that has introduced all kinds of crazy concepts that you're now struggling to keep in mind? Local branches? Remote tracking branches? Mutable branches? Really?

You don't have mutable branches in Git, I think he refers to commits mercurial don't allow you to alter (public ones).

Local branches in Hg is the same as bookmarks you havent pushed.

Remote tracking branches in Hg would be bookmarks you have pushed.

Those are all Mercurial concepts.

Well, no. These are _at most_ the names of various third-party extensions, which are not even distributed with Core.

Mercurial itself has just heads, which can be named or not. Bookmarks are orthogonal to the whole thing.

Mercurial without enabling extensions such as mq is simple only in the same sense that quilt is simple compared to git. Things quickly become more complex as you try to actually use it and need to enable extensions to do what you can do with git out of the box. The big benefit that git has over mercurial is that it has a powerful and expressive (and yes, complex) core concept. Mercurial quickly becomes a mess of, yes, orthogonal concepts layered on top of each other.

Anyway, you are plain wrong.

* Branches (named and unnamed) are part of core mercurial.

* Bookmarks are part of core mercurial.

* Multiple heads are part of core mercurial.

* Phases are part of core mercurial.

* Secret changesets is part of core mercurial.

* mq is distributed with Mercurial.

* Local branches is an extension that isn't part of core mercurial, I'll give you that. However, calling it a "third-party extension" is pedantic. It's listed on the official mercurial web site, and using extensions is much more a part of every day usage of mercurial than using extensions in git, for example.

edit: formatting.

Not all Git concepts exist in Mercurial. See more here: http://mercurial.selenic.com/wiki/GitConcepts

He's not saying that they are Git concepts that have analogs in Mercurial. He just listed off Mercurial concepts.

There was a thing going around twitter lately:

> If ping was designed by the git people: net-ping host --no=dns,bind --proto=TCP,rfc:492 eth0@ipv4:: -ADDR.ARPA --stats -v

I think it would be

    git checkout --ping
(Checkout already does too much; one more doesn't hurt).

That honestly doesn't have the truth ring of good satire for me... It seems to be making fun of the lack of sane defaults in git (maybe?), but if anything, git seems too focused on mysterious implicit configuration-controlled behavior, over explicit control.

Edit: Ah, hmm, maybe the satire is more along the lines of "a single command does too much stuff", which does ring true for commands like `checkout` and `reset`.

Comparing hg branches to git branches in this context isn't super-useful; the right comparison is to hg bookmarks. In this case the semantics seem to be (based on reading the documentation so I might be wrong):

  hg push [dest] -- Push all local bookmarks that match a remote bookmark
  hg push -B [dest] -- Push a specific local bookmark to a remote
To me those semantics don't seem particularly simple or flexible. In fact it seems quite like the semantics git is moving away from but with the restriction that local names and remote names always have to match, which means that you have to be very careful naming your local bookmarks to avoid clashes.

No it's not you. It's overly complicated. This is what has always irked me about computing--making something seem more difficult than needed. I'm not asking for for an Apple solution, just cut the bull shit--high brow--If you don't know GIT you shouldn't be programming. It's a repository. I shouldn't need a git pocket guide. I want things fast and efficient. I don't like to spend daylight hours figuring out things; life is too short. In reality, I don't even like sitting in front of a computing devise, but society now requires it.

Just curious, where is this highbrow "if you don't know GIT you shouldn't be programming" bullshit you speak of?

I guess 'simple' means "don't try to be too smart".

Pushing only the current branch by default is a good thing, I think. If you are using a more centralized setup you can change the configuration of push.default to 'matching'.

Perhaps "dwim" would be a better description of simple, but it arose from much feedback and debate on the git mailing list. Its behavior is now what it is believed most git newcomers expect.

Is this released already or are those just preliminary release notes?

The current version is still 1.9, but it shouldn’t take long for 2.0 to be the official stable release.

Minor feature that's really nice: the pull.ff config setting. I had made an alias for doing that manually, now I can start actually using git pull again.

Haha, me too, my lovely "git pfo" will have to go… Maybe.

The problem with git is that new options aren't simply ignored by old git versions, meaning that if you synchronize your gitconfig as part of your dotfiles, then the machines that have old git versions will start spitting error messages at every command for options specific to new versions. I learned that painfully with push.default=simple.

For `push.default`, older versions understood `push.default` but only later was the `simple` mode added.

For `pull.ff`, old versions will simply ignore the setting. I know because I wrote the patch ;-)

"git push -f" will no longer ruin days (as badly)

Possibly the most confusing default in git. My gitconfig has:

    config = default
        default = tracking
I once made a virtual machine and didn't pull in my usual .gitconfig. It ruined my day.

... due to force pushing multiple branches?

I've seen someone do it. If your workflow is 'git push -f feature' after rebasing, instead of 'git push feature -f', you can tap enter and break the world.

It really blows my mind that you say those two aren't equivalent. I now must read the man pages...

Edit did you mean to say (plus)feature or is something ruining the formatting? That seems to be how to specify only one branch. Yuck.

I'm lucky I haven't run into this, I guess, because I set my push default to simple a long time ago, so long ago I can't even remember why.

The two are equivalent if you type them in full, but if you stop one before typing the feature branch name, you've broken everything.

git push -f (enter) => Death to all branches. git push feature -f => Can only ever force push the feature branch

No matter when you press enter in the second line, intentionally or accidentally, you can't break all branches.

Ah, I see. Thanks for clarifying.

`push -f` and `workflow` should never be in the same sentence.

Exactly. Doing that by mistake (and then being taught to set `push.default` to upstream or simple) has been a rite of passage for engineers at my company.

I never quite understood why the default was what it was. I can count the times I've wanted to push all branches at once on no hands. But maybe that's just my work flow.

I have never had the need to force a push. What are the circumstances that would require it?

you have a private feature branch on git hub, clean it up via rebase (or just rebase to latest master) before review, and you need to force push it.

on long running features, you 1. want to save your state off of your laptop and 2. keep it clean for your own review and for others' review. thus, force push is required, otherwise you'd have to keep making new revs of your branch (branch named joeblow/my_feature_rev_4).

That looks so wrong to me. It says everywhere in the docs "never rebase something that's been published" and it says so for a reason.

The fact that git lets you shoot yourself in the foot doesn't mean you should, definitely not incorporate this into working procedures.

If it's a private feature branch, don't make it public (pushing would still back it up on the server, though you'd have to know the sha1 to fixed it). If it's public, don't rebase it.

> and it says so for a reason.

And yet you don't know the reason. It's because others may have merged your work or be dependent on it. In my case, that doesn't happen, because it's a private branch. I'm the only developer, but other people can look at it for review.

I like the "add" is more inclusive by default. But does this mean that "add -p" also can add untracked files? (If not, it seems inconsistent to me.)

Like it says in the man page, git add -p "effectively runs add --interactive, but bypasses the initial command menu and directly jumps to the patch subcommand". Interactive mode does support adding untracked files.

Not what I'm asking. "add -p" will offer deletions, but it should also offer to add untracked files, essentially showing a diff with all lines added (with an empty file as the base).

"add -p --all some_untracked_file" does nothing, "--interactive" does something completely different; a menu system, not a "yes/no/etc." patch prompt.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact