Working remotely has become much more common in web development over the last few years. Before version control, working remotely on the same development project would have been an absolute nightmare. Developers would have had to send large files to each other (probably through email), pasting in their own code before sending it back. There was no real way to track what had been added and when.
Thankfully, version control has arrived and made development on all fronts a lot more manageable. Web projects have become much easier to implement and manage, especially when it comes to working in a remote development team. You no longer have to worry about the current version of a website being overwritten – each team member is free to work on any file at anytime – and there is no confusion as to where the latest version of a file is being stored.
In this tutorial, we are going be using GitHub to manage our code. There are numerous different types of version control tool out there, such as Bitbucket and TFVC, but even though they are all different, the principles remain the same when it comes to managing code.
Firstly, it's very important to have a successful branching model when working in any team to make the development and deployment process run smoothly. You are most likely going to have multiple developers working on the same project. When working with a remote workforce, I believe the best workflow is composed of three main branches as well as a set of temporary ones:
- Develop branch: Every line of code has been tested and validated by the client.
- Staging branch: This will correspond to the validation environment.
- Release branch: This contains the last version of your website in production.
There will also be a set of feature branches. However, these will just be temporary to initially build out the new features.
Multiple developers on one project
Let's assume you run a team with two developers who work remotely. We will call them Sarah and James: they are both working on the same ecommerce website for a client. Sarah needs to develop a feature that registers the customer details.
We would break this down into three separate user stories – adding, editing and removing – and then add these three tickets into the sprint backlog.
So, let's say that Sarah begins on the adding customer details section. She would need to create the feature branch 'customer-details' and a user story one for the first task 'add-details'.
git checkout develop && git pull origin/develop git checkout -b feature/customer-details git checkout -b add-details
Sarah would continue to work on the temporary branch 'add-address' locally and commit her work as she develops. Now, let's say that James wants to help Sarah with the customer details feature, so he starts working on the details deletion.
James would pull the last version of the shared branch and create a new branch for the user story 'delete-details'. Then he can start making his own additions without worrying about overwriting Sarah's code.
git checkout feature/customer-details git pull origin/feature/customer-details git checkout -b delete-details
He will also use his temporary branch to code locally and commit any changes. Once Sarah has finished her feature locally, she puts the ticket into code review. She would push her code to the staging branch and open a pull request with the staging environment.
// She pushes her code to the staging branch git push origin add-details // She opens a pull request with the staging environment git request-pull staging add-details
We would now have the customer-details feature branch and the two user story feature branches in development 'add-details' and 'delete-details'.
Once her code has been reviewed, she can merge her branch into staging. The ticket is now in the validation column, waiting for the validation from the lead developer.
// She gets the last version of the staging branch git checkout staging && git pull origin/staging git merge add-details && git push origin staging // She builds the validation environment // and asks the product owner to validate
Once Sarah's work has been validated, the ticket can be moved into the done column. She can merge her work into the feature branch and start another user story, like deletion of customer details.
// She pulls the last version of the feature branch git checkout feature/customer-details git pull origin feature/customer-details git merge add-address && git push origin feature/customer-details
When the whole feature has been validated by both the lead developer and client, Sarah can merge the feature branch into develop, as it's ready to go.
// She gets the last version of the develop branch git checkout develop && git pull origin/develop git merge feature/customer-details && git push origin develop
Deploy to production
Once all is complete and it's ready to deploy into production, James merges develop into release and launches the deployment. At this point he would know that all code is correct and the client is happy. He tags the commit of the release to get the history of each version.
git checkout develop && git pull origin/develop git checkout release && git pull origin/release git merge develop && git tag 2.1 git push origin release --tags
Rules to follow for this workflow
This remote development workflow can be pretty difficult to understand at first but if you get your team to work by this method, then you have a free working flow without the need to panic about files being overwritten or your developers working on the same area.
There are some key things to remember:
- The first thing you will need to teach your remote developers is your version control workflow and make sure that they are all reading from the same book.
- If you are developing a feature, try to break this down into smaller user stories. This way it's easier to keep track of every commit.
- Don't miss out any steps: the same workflow must be followed each time.
- You will always need to merge your branch into develop to prepare the next release.
- You should clean the staging repository every week if possible. You should delete the staging branch, locally and remotely, and recreate it from develop branch – see example below:
git co develop && git pull origin/develop git branch -d staging && git push origin --delete staging git co -b staging && git pull origin staging
With smaller projects, you may want to use a less complex workflow. You could use master, which contains the most up to date version, a develop branch and then a set of branches for each additional feature – whether that be forum, contact form, checkout system. It all depends upon your personal preference.
Managing merge conflicts
Dealing with merge conflicts is difficult enough if you are all working in the same room but they can become even more of a nightmare if you are all working in a different office. The most important thing is to remember that you can always undo a merge and revert back to the state before the conflict occurred.
Whether you are doing all of the merges as lead developer or your team are the ones doing them independently, the first step is to understand what has happened.
- Did one of your co-developers edit the same line in the same file?
- Did they delete a file that you modified?
- Did you both add a file with the same name?
Git will tell you that you have unmerged paths via git status:
$ git status # On branch checkout-system # You have unmerged paths. # (fix conflicts and run "git commit") # # Unmerged paths: # (use "git add <file>..." to mark resolution) # # both modified: checkout.html # no changes added to commit (use "git add" and/or "git commit -a")
Now, the most common cause of a conflict is when changes affect the same files on the same line. So, let's have a look at the contents of the conflicted line. You will notice that Git is really good in the fact that it will mark the conflicted area by enclosing it in <<<<<<<HEAD and >>>>>>>[other/branch/name]. In this case, it's checkout-system.
<<<<<<< HEAD This line was committed while working in the "user-form" branch. ======= This line, in contrast, was committed while working in the "checkout-system" branch. >>>>>>> refs/heads/checkout-system
The contents after the first marker originate from your current working branch. After the angle brackets, Git tells us which branch the changes came from. A line with ======= separates the two conflicting changes.
You can now simply open the file in an editor, search for the conflict markers and make any necessary modifications. When you're done, the file needs to look exactly as you want it to look or, alternatively, you can tell Git that you'll simply go with one of the edited versions, called ours or theirs.
git checkout --ours path/to/conflict-file.html
There are also many merge tool applications that can help with this. Kaleidoscope is a great one for Mac.
Project and issue management
It's just as important as a lead developer to have a project management tool to manage things such as tasks and bugs, especially when your developers are not office based. There are numerous solutions out there, such as ZenHub and Asuna, but I believe GitHub's built-in project and issue system is the best.
You can do things like set up a new project, create boards or assign issues. And don't just confuse issues with problems: you can also use it for enhancements, questions and bugs, among other things.
Here are a few of its best features:
- Built-in tagging system: Allows you to organise and prioritise your workflow and easily search through projects for relevant information.
- Milestones: Perfect for associating issues with specific features or project phases, such as bugs that need to be fixed before a beta launch or tasks to be completed in October.
- Multi assignments: Issues can be assigned to users in bulk, saving time and making you more efficient.
- Commenting: Engineers and management teams can easily discuss progress and results at every step of the way using the inbuilt commenting system.
- Task lists: Larger issues can be broken down into stages to discourage the creation of dozens of microscopic issues, keeping all of your work in the same place.
- Markdown format: The ability to use markdown formatting will prove popular with your developers and it can be used in most places around GitHub.
- Project boards: These can be used to house issues, pull requests and notes, categorising them as cards in columns of your choosing so you can look at larger projects as a whole.
- High security: You can trust GitHub to keep your data safe and it's harder to breach than most other project management systems.
Setting up a project
If you go to GitHub and then head to one of your repositories, you will see a tab that is called Projects. From there you can select New Project, set up your project details and create a new project template.
If you now select the Issues tab that is along the top and select New Issue, you will be able to create a new issue. You can then apply various labels – these are things such as bug, enhancement, question and duplicate. You might also use enhancement for a new feature or request. You can then assign various team members to the task, a milestone and also the project you just created.
Assigned members will then have a list of all their tasks and you can even use the project board to keep a track of what's currently being built. If you remember our earlier tutorial, we were talking about moving tickets to sprint backlog and validation. So GitHub works really well as an all-in-one tool for overseeing a project.