I am new to git and while I can see the immense benefits of the branch/merge process on individual projects, it also seems to me that another useful application of Git is to use it for centralizing the core custom code and templates that you often use in all your projects, with each project starting off as its own branch.
For example I have a large set of custom code that is just a starting place that I use for all apps. If I tweak it here and there, or find bugs and fix them, I want that to replicate through all projects that use the code.
By working on tweaks in a separate branch off the master, then merging back to the master, and then merging the master with other branches that occupy separate projects, it would seem I can achieve this quite well.
Are there any major drawbacks to this approach to Git?
Also while I know that submodules exist, I prefer not to use them at this time since they are not natively supported in Xcode.
Several projects will tend to advance on their own terms. If you have all together on the same branch, you see intermingled commits, and there isn't any sense of history to be discerned. If you place each project on a separate branch, you'll have to jump from one to the other, and there won't be any advantage against separate git repositories (git is very lightweight!).
A DVCS does add overhead (if there are several repositories with the same contents, it certainly adds disk space; but that is dirt cheap nowadays...). It has the advantage that you can work anywhere, freely (no need to wait for a slow connection), and (at least with git) the operations are normally so fast that until you get used to it you have this lingering fear that you are being cheated and nothing has been done...
For development, the fact that branching and merging works and is cheap means experiments and exploration are encouraged. The fact that commits are instantaneous and use up very little space leads to microcommits (one logical change, even a minimal bugfix or typo, per commit), instead of "a morning worth of work" dumps. This makes history understandable, and tools like git bisect extremely useful.
I have a bunch of git repositories with stuff I want to preserve history on, but not necessarily ever share with anybody else. Some more important of that stuff I keep also in remote repositories (not much more than git and ssh at the other end, and a bit of discipline to push there now and then, are required) for backup. In that sense, I use git more as a local VCS, which also has the advantage that I can share with others ;-)
Related
In Countinous Delivery book, it's recommended to keep everything - including CI scripts - in the version control. Actually, current CI systems like gitlab CI already follow this rule of thumb and search for CI scripts in the same codebase.
On the other hand, we are versioning our codebase (and it's built artifacts) whenever it changes. And we follow semantic versioning for that; incrementing patch field for bugfixes, minor for non-breaking features, and so on...
And we make sure the version is incremented between commits by checking it in the CI.
But, there are commits that only change the CI scripts; i.e. adding an analysis job, optimizing another, etc.
My question, after this long boring preface, is that what is the best practice to versioning such changes to the CI? Since it possibly can affect the final built artifact (e.g. changing a build flag in the CI job for optimization or ...).
Is it ok to increment the version in this case?
Git is a revision control system. Every time you commit something to a git repo, it labels the content of the repo with a content hash value that represents that version of the repo. Semantic versioning of a git repo's content is redundant and pointless. The whole point of SemVer is to provide a means for producers to communicate risk to consumers. In other words, semantic versioning is intended for build product labeling, not the bits that go into producing the build.
If you attempt to apply SemVer semantics to the repo, you are labeling the product inputs, not the product itself. You should not apply a SemVer string until after all unit/regression/acceptance tests have been performed. How else can you have any certainty whether the code/build-script changes have broken anything?
Pre-build labeling cannot work. Build processes that are capable of reproducing the exact same output twice in a row, are extremely rare, if any exist at all. It is a violation of best practice to have multiple API's/packages in the world with the same SemVer string attached to them. If you label the repo content and then forward that label to the build output, every time you run the build, you produce a package with different content. There will always be some risk that more than one of those outputs will be released into the wild. Many security conscious consumers pay close attention to the content hash of packages they consume. Detecting that a particular producer has released multiple package hashes without bumping the version number, will raise red flags and lead to mistrust of that producers internal processes.
This is a very deep topic that can't be fully covered here. Other issues to consider are OS/Compiler/Tool chain updates. Will you also be committing the entire build tool chain to the same repo? This is an untenable approach, full of hazards I cannot fully enumerate, without taking a few months off work to document them.
Best practice:
Use semantic commit messages that clearly state the developer's intent.
Validate build outputs prior to packaging/labeling.
Always keep humans in the loop, for non-prerelease publications.
Just for clarity, let me add that maintaining build scripts and tool manifests in the repo is considered a best practice. It ties the versions of your scripts and tools, to the versions of the code you are building. Git does do this job quite well, by creating a commit hash that encompasses the state of the entire repo (minus the tags if I recall correctly). But there will be issues eventually, with older versions of tools, being withdrawn from file shares/feeds, particularly when they are found to create security vulnerabilities.
It will sometimes be the case, that older versions of your products, cannot be reproduced using the earlier build process. Checking in the binaries is often promoted as a fix for this issue, but I would argue that it's an anti-pattern. Binaries you are likely never going to want or need in the future, should not be stored in your repo. It just clogs everything up.
Consider using an alternate archival system. Maintaining a separate archive of older tools isn't a bad idea, but you will often find that you simply can't run them on current hardware and OS's, without significant reconfiguration of build machine(s) and re-introducing well known security risks. You should frequently prune such an archive, based on the latest known risks and weighing the cost of having to do some additional work, if/when the day ever comes, that you need to build from a really old commit hash.
It is better to maintain an up-to-date build system, that can build all of your code base, back to some reasonable point in its history. That point is usually the oldest bits that you are willing to actively support with bug fixes.
These days I'm using SemVer compatible Headver; https://github.com/line/HeadVer and feeling happy.
It is very CI friendly thanks to the automatic incremental versioning, but still be able to announce when breaking changes happens by allowing to define major version number manually.
Question: What is the best way to maintain a project based on another OSS project, through Xcode and version managed by SVN?
I'd like to start a fork (?) of a reasonably popular open source project (it's allowed). Mostly, I want to build my own user interface written in Cocoa/ObjC for it and throw in a few custom features of my own as well.
Now, this OSS project isn't exactly small. The project itself has over 3000 files, and the build process is pretty intense- consisting of multiple stages and steps, which need to compile build tools, run those, then compile the results.
All this is fine and dandy in Xcode, since it's easy enough to setup build phases and rules to handle everything.
What I'm not clear on, is how best to manage patches from upstream. They are constantly working on the project and I'd like to be able to keep up to date with those patches as easily as possible, as many of the diff files effect sometimes up to a hundred (!) files at once.
So maintaining a pristine unmodified copy of that source tree so I can apply patches to it seems like a smart thing to do, because I really don't want to be sorting through hundreds of files every few weeks merging patches by hand.
What I'm thinking of doing in this regard is:
1) Setup an "upstream" SVN repo to hold a copy of the upstream source, plus the bare minimum required to compile it in Xcode (so an xcproject, a few xcconfigs, some prefix header files and that's it)
2) Setup my own "downstream" SVN repo where I do all my work and apply my own modifications.
Whenever upstream releases a patch, I can apply it to #1 then synchronize across to #2, and deal with any issues created by my own modifications.
What I'm not clear about, is if this is a sane way of handling things- or if there's some better practice I should be following.
Is this the best way to handle things, or should I be looking at doing this some other way?
In SVN-world it was named "Vendor Branches" long time ago and intensively used by many teams (you can additionally google this phrase)
Technically it's
one SVN repo
at least one special branch (special in terms of usage, nothing more), which, with svn:externals, linked to 3-rd party repo of upstream code
your place for changes (trunk or any other place, I prefer trunk), initially created as copy of vanilla code and there you perform all code-hacks
If (or "when") vendor branch got updates from upstream, you have just merge branch to /your place/, integrate changes and continue to work
I've been doing some reading about continuous integration recently and there is a scenario which could occur which I don't understand how to deal with appropriately.
We have a stable mainline/trunk branch and create branches for features. Each developer will keep their own feature branches up to date by merging from trunk into their branch on a regular basis. However it is entirely possible that two or more feature branches could be created and worked on over a period of several weeks or months. In this time many releases of the software could be deployed. This where my confusion arises.
It is very likely that changes for one feature branch will cause merge conflicts with other feature branches. CI suggests you should merge into trunk at least daily which would resolve the conflicts quickly. However, you may not want to merge the feature code into trunk because it may not be finished or you may not want that feature available in the next release. So, how do you deal with this scenario and still follow CI principles of daily code integration?
There are no feature branches in proper CI. Use feature toggles instead.
The idea explained more fully in this article is to merge from the trunk/release branch to feature branches daily, but only merge back in the other direction once a feature meets your definition of 'done'.
Code written by one feature team will be pushed into the trunk once it's complete, and will be 'distributed' to the other teams, where conflicts can be dealt with, as part of the daily merge process.
This doesn't go as far as satisfying Nick's desire for a version control system that can be used a backup tool, unless the changes being made are small enough that they can be committed to the feature branch within a timeframe where the the risk of losing your work is acceptable.
I personally don't try to reintegrate code into the release branch before it's done, and although I've never really tried, I'm sure building feature toggles in for unfinished work has its own issues.
I think they mean merging mainline into the feature branch, not the other way 'round. This way, the feature branch will not deviate from mainline too much, and be kept in an easily mergeable state.
The git folks do the same thing by rebasing feature branches on top of the master branch before submitting a feature.
In my experience with CI, the way that you should keep your feature branches up to date with the main line changes as others have suggested. This has been working me for several releases. If you are using subversion make sure you to merge with the merge history enable. This way when you are trying to merge your changes back to line it will only like you are merging the feature changes to line, not trying resolve conflicts which your feature might have with the main line. If you are using more advance VCS like git the first merge will be a rebase where the second will be a merge.
There are tools that can support you to get thins done more smoothly like this Feature branches with Bamboo
Feature branches committing back into the mainline, and OFTEN is an essential feature of Continuous Integration. For a thorough breakdown, see This Article
There's now some good resources showing how to combine both CI and feature branches. Bamboo or Feature Branch Notifier are some ways to look.
And this is another quite long article showing pros of so called distributed CI. Hereunder, one excerpt explaining the benefits:
Distributed CI has the advantage for Continuous Deployment because it keeps a clean and stable Mainline branch that can always be deployed to Production. During a Centralized CI process, an unstable Mainline will exist if code does not integrate properly (broken build) or if there is unfinished work integrated. This works quite well with iteration release planning, but creates a bottleneck for Continuous Deployment. The direct line from developer branch to Production must be kept clean in CD, Distributed CI does this by only allowing Production ready code to be put into the Mainline.
One thing that still can be challenging is keeping the branch build isolated so that it doesn't pollute your repository of binaries by pushing its branch builds to it. Bamboo seems to address that, but not sure it's as easy with Jenkins.
We're considering a switch from SVN to a distributed VCS at my workplace.
I'm familiar with all the reasons for wanting to use a DVCS for day-to-day development: local version control, easier branching and merging, etc., but I haven't seen that much that's compelling in terms of managing software releases. Here's our release process:
Discover what changes are available for merging.
Run a query to find the defects/tickets associated with these changes.
Filter out changes associated with "open" tickets. In our environment, tickets must be in a closed state in order to merged with a release branch.
Filter out changes we don't want in the release branch. We are very conservative when it comes to merging changes. If a change isn't absolutely necessary, it doesn't get merged.
Merge available changes, preferably in chronological order. We group changes together if they're associated with the same ticket.
Block unwanted changes from the release branch (svnmerge block) so we don't have to deal with them again.
Sometimes we can be juggling 3-5 different milestones at a time. Some milestones have very different constraints, and the block list can get quite long.
I've been messing around with git, mercurial and plastic, and as far as I can tell none of them address this model very well. It seems like they would work very well when you have only one product you're releasing, but I can't imagine using them for juggling multiple, very different products from the same codebase.
For example, cherry-picking seems to be an afterthought in mercurial. (You have to use the 'transplant' extension, which is disabled by default). After you cherry-pick a change into a branch it still shows up as an available integration. Cherry-picking breaks the mercurial way of working.
DVCS seems to be better suited for feature branches. There's no need for cherry-picking if you merge directly from a feature branch to trunk and the release branch. But who wants to do all that merging all the time? And how do you query for what's available to merge? And how do you make sure all the changes in a feature branch belong together? It sounds like total chaos.
I'm torn because the coder in me wants DVCS for day-to-day work. I really want it. But I fear the day when I have to put the release manager hat and sort out what needs to be merged and what doesn't. I want to write code, I don't want to be a merge monkey.
You really want to be using git in this situation, because it is so vastly superior when it comes to merging and release management. Git allows for a signoff process for changes to go to release; it actually provides support for multiple layers of release management, precisely because that is how Linux is managed.
Simply put each release in a branch. Instead of blocking out changes you don't want, accept only those that you do, by only signing off for release those changes that are going into a release.
Git also allows you to cherry-pick a collection of changes into a single patch to be sent upstream, so you don't have to carry all the 'oops, that didn't quite work' patches into the release branch or repository, only nice clean feature or fix patches.
Just moved to subversion...from visual studio. I love it already! Can someone briefly explain
Repository
Branches
Tags
Trunk
Do I need to create a new repository for every project? Or a new trunk?
Thanks
You don't need a separate repository, but you can if you want. I recommend reading the book at http://svnbook.red-bean.com/. Grab the pdf version or whatever. It doesn't take too long, and it explains some things pretty well. I read it, and found that I'm glad I did.
Remember that subversion is just a fancy filesystem that supports versioning. Think of a repository as a "drive root" like "C:/".
Each project gets a trunk, tags and branches directory. All of your day to day work happens in the trunk. Experimental code is done in a branch and then merged back into the trunk at a later date. Tags are for when you release the software. These are not to be edited. When you release the software, you create a tag with a unique name based on what is currently in the trunk.
I can't say whether or not you need a separate repository for each project, there are pros and cons. This blog posting details them:
Simplified administration. One set of hooks to deploy. One repository
to backup. etc.
Branch/tag flexibility. With the code all in one repository it makes it
easier to create a branch or tag
involving multiple projects.
Move code easily. Perhaps you want to take a section of code from
one project and use it in another, or
turn it into a library for several
projects. It is easy to move the code
within the same repository and retain
the history of the code in the
process.
Here are some of the drawbacks to the
single repository approach, advantages
to the multiple repository approach.
Size. It might be easier to deal with many smaller repositories than
one large one. For example, if you
retire a project you can just archive
the repository to media and remove it
from the disk and free up the storage.
Maybe you need to dump/load a
repository for some reason, such as to
take advantage of a new Subversion
feature. This is easier to do and with
less impact if it is a smaller
repository. Even if you eventually
want to do it to all of your
repositories, it will have less impact
to do them one at a time, assuming
there is not a pressing need to do
them all at once.
Global revision number. Even though this should not be an issue,
some people perceive it to be one and
do not like to see the revision number
advance on the repository and for
inactive projects to have large gaps
in their revision history.
Access control. While Subversion's authz mechanism allows
you to restrict access as needed to
parts of the repository, it is still
easier to do this at the repository
level. If you have a project that only
a select few individuals should
access, this is easier to do with a
single repository for that project.
Administrative flexibility. If you have multiple repositories, then
it is easier to implement different
hook scripts based on the needs of the
repository/projects. If you want
uniform hook scripts, then a single
repository might be better, but if
each project wants its own commit
email style then it is easier to have
those projects in separate
repositories
I agree, read the svnbook. It's a great resource.
Do I need to create a new repository for every project? Or a new trunk?
Kevin covered the single/multiple repository trade-offs pretty well. When we started with svn, we used one repository for all of our development projects. It worked well and had all the advantages mentioned. However, as the repository got bigger it got more difficult to administer because of the size of the dump file and resulting issues during backup. It also became an issue that projects couldn't easily be archived out of the repository - it's certainly possible but it requires dumping and pulling out projects from the repository. They aren't issues you can't get around but it's something to keep in mind.
Repository
Branches
Tags
Trunk
Branches, tags and the trunk are just copies of your files contained in the repository. It allows you to segregate and check-mark your files at whatever time you feel appropriate (usually at a release or a feature branch).
An important thing to keep in mind about branches, tags and trunk is that they just conventions in svn. There is no functional difference between the three locations, they are just an accepted usage model and they can be changed or organized differently if you have a good reason. I'm not recommending that you organize differently but you'll find that svn is very flexible because there isn't really a forced organizational structure other than convention.
Depending on how many projects you decide to have in your repository, you may organize differently.
You can have the subdirectories with projects under it:
\repo
\branches
\...
\tags
\...
\trunk
\..
or you can have projects contain the subdirectories:
\repo
\Project1
\branches
\tags
\trunk
\Project2
\branches
\tags
\trunk
There are trade-offs that are covered in the svnbook. The first method is usually used if you only have one project per repository and the second if there is more than one project in your repository.
The nice thing is that you can just start using svn and then figure out what you prefer. You should have some sort of organization but, with cheap copies, you can always re-arrange the folders as your situation or workflow changes.
An important thing to remember with SVN, compared to other version control systems like CVS or Git, is that SVN doesn't really have a concept or branching or tagging. As far as SVN is concerned it's all just a bunch of folders and files. So while you'll see a lot of people using the branches/tags/trunk setup, this is not required and you are able to deviate from this if you so choose.
Generally speaking 'trunk' is where you keep your active development going. So this is where you do all your commits. Whether or not you checkout trunk or use tags/branches instead is entirely up to you.
Branches, as I've used them, are usually for when you need to do large changes to your application but don't want them in trunk because you want to be able to continue developing against trunk without deploying your other changes. In this case you may have something like
\repo
\trunk
\branches
\version_two
In this case you can develop in both trunk and version_two separately and, assuming your live site is a checkout of trunk, you don't need to worry about 'accidentally' breaking your live site with your other changes. And when those changes are done and ready you just merge them back into trunk whenever you want.
Tags can be used similarly to branches, in that instead of checking out trunk and just using 'svn up' to update your repository you instead of several tags, each representing one release. So your repo may look something like
/repo
/trunk
/branch
/version_one
/version_two
/tags
/1.0.0
/1.0.1
/1.1.0
In this case the general idea is that when you're ready to do a deploy you do an
svn copy
To copy trunk over to a tag (in this case the next one could be 1.1.1, 1.2.0, 2.0.0, etc). How you name your tags it entirely up to you though and, again, depends on your project and requirements. With this route instead of doing a regular 'svn up' you would have to do an svn switch. So you have to deploy with
svn switch https://svn.yourrepo.com/repo/tags/1.1.0
The switch will automatically do updates, adds and deletes on the appropriate files.
When it comes to one repo for many projects or separate repos for each one I am an advocate of one repo per project. It provides the additional benefits of easily managing access to it. But most importantly it means that each project has a separate commit history and separate logs. This m
Reading your tags I see you started using VisualSVN instead of your old VSS system. (Your question says you stopped using Visual Studio.. which makes VisualSVN a strange choice).
One of the major differences between SourceSafe and VSS is that you can choose different tools to access the same repository (and you can switch every time you like as they all share the same workingcopy).
E.g.:
TortoiseSVN for Explorer integration.
The normal subversion client for scripts.
VisualSVN as Visual Studio frontend for TortoiseSVN
AnkhSVN as real SCC (VAPI) package in Visual Studio.