Branches are just mutable pointers to commits. You're imposing a mental model onto Git that simply isn't present.
Git is revolutionary, in part, because instead of asking "what's the mental model we want to emulate and then never mind if that matches the implementation", they gave developers credit that they can understand a handful of simple concepts and made the actual design and data model as simple as possible. Programmers know what pointers, SHA-1 hashes, and DAGs are, so just use them.
You're making the same mistake as GP. I love Git, and I know that asking "what branch was this commit on" makes no sense. My point is that some users have different requirements as to what a DVCS should provide. If Git can't fulfill some of these requirements, then just say "Git can't do this" rather than beating around the bush.
I'm saying that "for the user" is a distinction not necessary for a tool designed for the type of people who actually know how software works. For the user, Git does the same thing that it does for the programmers who wrote Git. There's only one side of it. It's not two-faced like most software. The only possible explanation is to explain how Git works.
No, a possible explanation would be 'that is unnecessary, because: ...'. Except of course tagging commits with branches is not unnecessary, because that's the only way a user might make sense of ancestors of a merge commit...
Unless you like manually tracking parents of a commit, and trying to guess which branch is which based on commit messages. Fun!
I've seen many workarounds to this clear deficiency, the simplest of which is simply putting the branch name at the start of the commit title. Of course that usually cuts the space available for the actual commit title down from ~60 characters to 20-40, depending on how verbosely you call your branches.
> Unless you like manually tracking parents of a commit
Git tracks the parents of a commit. There are ways to visualize that, even with command-line git. When you do this, it's usually clear which branch is master and which branch was the feature branch, and since the merge commit has a default commit message like "merge <<branch-name>> to master" it's even easier to figure out.
It's also entirely possible to use a Git workflow where you rebase your branches onto master before merging then in with a fast-forward, which means there are no merge commits. This workflow usually involves squashing. Conversely, you can use a workflow where you never fast-forward merge to master, in which case master is the branch that consists of a series of commits called "merge <<branch-name>> to master".
Open `git glog` and look at the tree is exactly what I ment by manually tracking parents of a commit. I shouldn't have to do that.
That means that to see commits that were done in a particular feature branch I need to do some magic that walks up the commit tree from a given merge commit, guesses which one of the parents is the master and which one is the feature branch, remembers the commit ids, keeps track of merge commits it hits and makes sure it is still tracking the right branch (merges of master into a feature branch are common, merges of feature branches into other feature branches are occasional), etc.
All because gits branches aren't really branches at all.
As to fast forwarding a feature branch onto master, I can't believe anyone would actually do that. You might as well be developing on the master branch from the beginning there, what's the point of having branches if they disappear from history?
I have to admit some confusion. You're not looking through your commit history when you're trying to figure out which branch a historical commit was on?
The reason for the rebase/fastforward workflow is to basically synchronize changes. You might have five developers working on seven different feature branches at a time. But they're only going to be merged back to mainline in the order they're completed, which you don't know ahead of time. Once they're merged back, you don't necessarily need to record the history of the feature branch separately. Often you're going to squash changes anyway.
It's also a better idea to rebase from master and merge to master, but even if you merge both ways, the commit message still reports the source and destination branches. If you're disciplined about using feature branches, master is the branch with commit after commit saying "merged to master".
>I have to admit some confusion. You're not looking through your commit history when you're trying to figure out which branch a historical commit was on?
I shouldn't have manually filter the commit history to get the information that interests me.
>The reason for the rebase/fastforward workflow is to basically synchronize changes. You might have five developers working on seven different feature branches at a time. But they're only going to be merged back to mainline in the order they're completed, which you don't know ahead of time. Once they're merged back, you don't necessarily need to record the history of the feature branch separately. Often you're going to squash changes anyway.
But if you fast forward your changes on top of master and push that out as the new master, you lose all the benefits of branching. You could have as well made your changes on master, do pull --rebase once you've completed and then push out. That's how the history looks like.
>It's also a better idea to rebase from master and merge to master, but even if you merge both ways, the commit message still reports the source and destination branches.
Sure, if the rebase is clean, but conflicts are common.
>If you're disciplined about using feature branches, master is the branch with commit after commit saying "merged to master".
Unless you use the github UI, in which case it will say 'Merge pull request ...'. Or you had to hotfix something on master - it happens.
> But if you fast forward your changes on top of master and push that out as the new master, you lose all the benefits of branching. You could have as well made your changes on master, do pull --rebase once you've completed and then push out. That's how the history looks like.
Which benefits?
To me, the main benefits of branching happen as I'm developing a feature. I can work on something and quickly context-switch either back to master or to a different feature branch. For instance, if I'm working on a feature but a high-priority bug fix needs to be done first, I can switch back to master, check out a bug fix branch, and keep my feature work separate from it. When the bug fix is done, I merge it in and rebase my feature branch from it. The only thing I really care about historically is that features land in master all-at-once, which squashing, rebasing, and fast-forwarding does for you.
> Sure, if the rebase is clean, but conflicts are common.
You have to resolve conflicts either way though.
> Unless you use the github UI, in which case it will say 'Merge pull request ...'.
Still a recognizable pattern.
> Or you had to hotfix something on master - it happens.
That's called "not being disciplined about using feature branches". I suspect you run into this problem because you're suffering under a self-imposed constraint that branch names have to be globally unique and meaningful throughout your version history.
This isn't a problem unless you want to enforce a workflow where you always merge to master--the rebase/squash/ff workflow wouldn't actually pose a problem here, since all ancestor commits to master were deliberately put on master. My point is, if you follow an inconsistent workflow, no wonder your history is difficult to look through.
Someone who can't understand the Git data model is, by programmer standards, a fool. If you actually understand the data model and have reasons for not liking Git, I'm curious what they are. Unfortunately, most criticisms come from people who can't be arsed to grok how Git works and just ragequit.
>If you actually understand the data model and have reasons for not liking Git, I'm curious what they are.
Well, the fact that I can't easily find what commits were done on a branch, for one. And yes, I understand why it's not possible, they way git does branches.
Or that it doesn't track renames/moves, other than on similarity basis that often fails to detect rename when viewing a file history, for example.
The git answer to both of these is usually 'well your viewer could be doing that', except they don't, because it's hard when you don't track that information in commits.
Lets back up: why are you trying to figure out what branch a historical commit was on? What problem does that solve for you? I've never found that information terribly important or interesting.
Say I bisect some issue to a particular commit. Knowing which branch it was made on tells me what issue it was trying to solve, which gives me context for the entire branch.
It also means I can easily request all commits made in the master branch, to see what features were merged in recently.
> Say I bisect some issue to a particular commit. Knowing which branch it was made on tells me what issue it was trying to solve, which gives me context for the entire branch.
How is the branch name going to give you sufficient information on that anyway? You're going to have to look at the commit message and probably the surrounding history anyway if you want context for the entire branch.
> It also means I can easily request all commits made in the master branch, to see what features were merged in recently.
In this use-case, you're probably viewing some form of "git log" anyway, so it's not hard to turn on the option that shows the tree view, which should make it readily obvious.
>How is the branch name going to give you sufficient information on that anyway?
Well, in my workflow it will give me the issue number, since branches in my repo all look like '530-issue-description'. I suppose that's because we used to work with mercurial, where that is actually meaningful and helpful.
>In this use-case, you're probably viewing some form of "git log" anyway, so it's not hard to turn on the option that shows the tree view, which should make it readily obvious
The tree view will still interleave master commits with all the other commits, and if there's a lot of parallel branches and significant distance between master commits it's easy to get lost.
Tracking your single 'pipe' character down a couple pages and not losing which one you're watching... Not what I call good UI.
Going back to my comment, I think for a lot o peole it's not that they can't understand the Git data model, it's that they:
1) don't magically know that they're supposed to understand the data model in order to use it
2) Come for help when they screwed up because they don't understand it and are basically told "You screwed up because you're an idiot"; since they are already in a bad mood, they then ragequit.
Git is revolutionary, in part, because instead of asking "what's the mental model we want to emulate and then never mind if that matches the implementation", they gave developers credit that they can understand a handful of simple concepts and made the actual design and data model as simple as possible. Programmers know what pointers, SHA-1 hashes, and DAGs are, so just use them.