confused about creating nested branches in git
I just started using git and started collaborating with other developers on same code. I have worked a little with SVN before but never had to collaborate with other people on my codebase.
Now with collaborators working on same code, I need an efficient workflow. While searching for such, I found this, and it seems like a good workflow for our requirement.
My repository resides in a local machine. I created the repository with
git init --bare. I added the initial codes to master and pushed it. Then I added a “develop” branch using
git branch develop; git push -u origin develop.
Now I want to create feature branches from “develop”, and I want these feature branches to be accessible by all collaborators. I wish to have a nested structure, something like this
origin/master origin/develop origin/develop/newFeature origin/develop/anotherFeature etc.
so that when a collaborator types in
git branch -a he/she will immediately know the “newFeature” is in the “develop” line, and decides what to do.
So after some trial and error, this is what I did:
git clone file:///path/to/repo --branch develop git checkout -b newFeature develop EDIT some files git add . git commit git push origin newFeature
Now this “newFeature” is available for all collaborator to clone.
git branch -a gives me
develop * newFeature remotes/origin/HEAD -> origin/master remotes/origin/develop remotes/origin/master remotes/origin/newFeature
So is the “newFeature” really part of the “develop” branch? Or is it now branch by itself? Once I clone the “newFeature”, how do I check whether it is the develop line? This may potentially be confusing as I may end up having a branch named “newFeature” in master in due time!
My understanding of how git works is definitely inadequate. Therefore, if anyone can point me to right direction, that will be great!
One Solution collect form web for “confused about creating nested branches in git”
TL;DR version: just
git checkout -b develop/feature initially (you’ll need to not have a branch named
develop for this to work though!).
Branches don’t really “nest” for a ridiculously simple reason: a branch name (like
newFeature) merely stands in for some commit-ID, i.e., some SHA-1 “true name” of some commit.
(In this respect, a branch name is the same as a tag, like “v2.3”.)
The thing that makes (local) branch names special—what makes them different from any other reference—is that “git checkout” will let you get “on a branch” by writing the name of the branch in git’s
HEAD file, and, once you have done that, making a new commit will automatically update the branch-name so that it points to the new commit you just made.
(Remote branch names can’t be gotten “on” this way, but will also change their target SHA-1 as needed. I mention this only because the next paragraph mentions “remote branches” or “remote-tracking branches”, which you’ll see in
git branch -r output.)
Branch names are, however, sorted by
git branch --list (after sorting by “kind”, i.e., grouping all local branches together first, then all remote branches). This means you can have the names grouped together: just create the names as
develop/newFeature originally. The slash is, in this case, merely a part of the name.
The problem here is that git originally implemented1 these branch names by putting them in directories containing files. On the systems that support git, you can’t have a directory named
develop and a file named
develop at the same time.2 So if you have a branch named
develop, git may have created a file (
.git/refs/heads/develop, specifically), which then prevents it from creating a directory (
.git/refs/heads/develop, again) containing the file (
newFeature) containing the SHA-1 of the commit that the branch currently identifies.
1While git now also uses a flat file (
.git/packed-refs) to store branch-to-SHA-1 mappings, it still also uses directories of files, and must make sure that you don’t create a name that must serve as both directory and file.
2Personally I think it makes sense for a file system name entity to work as both directory and file: this would be a way to, for instance, store all the ELF sections of an executable as files within the directory that is the executable program, or handle the things that MacOS does for app bundles. But this violates all kinds of rules for the way things must work in POSIX, so it would require a major redesign of the file system name space(s), and would be more suitable as a follow-on to Plan 9 (for instance) than as a Unix-ish variant.