Proper team etiquette will assist your team to achieve seamless collaboration and productivity. These rules are often gained with experience as most developers who are starting to grasp challenging new concepts do not prioritize proper Git etiquette. Even though these rules might not seem essential at first, they are immensely helpful during debugging, merging code, and managing pull requests.
This post aims to help you maximize your team’s use of Git by discussing etiquette pointers that will support you when creating branches and commits, as well as handling unnecessary, private, or large files. In addition, we will look at the different commands we can use to amend common mistakes that could hurt your workflow and team collaboration.
Branches
A repository always has a main branch called origin/master
, which reflects the production-ready state or already deployed code, and developers branch and merge from it. During the implementation of a project, many supporting branches will be created. These branches should have a specific purpose, a limited life time, and a descriptive name. Here are some guidelines to create effective branches:
Create a branch per issue. You will have to create a merge request at some point in order to get your supporting branch merged into master. Merge requests are a great opportunity for feedback that will help you grow. Overly long merge requests get procrastinated or simply not reviewed in detail. In other words, you would miss out on getting feedback from your team that would help you grow.
Use a token at the beginning of your branch name. Tokens are groups agreed by your team that quickly communicate in which part of your workflow each branch belongs. Some popular tokens are feature/ or feature- and bug/ or bug-.
Note: The use of
/
in your naming convention might break your CI/CD pipeline if using Jenkins or other third-party tools. Make sure you talk to your team before choosing a token name convention.
This convention also allows you to list them by group:
git branch --list “feature/*”
Include issue number. This comes handy when your issues are not automatically linked to your branches. For instance, my team is currently using JIRA to track issues and Gitlab as our Git repository hosting service. It is really nice to be able to glance at a branch and know which issue it belongs to.
Use a descriptive and short name. Do your best to select short and well-defined names that communicate the task’s purpose clearly.
A well-thought-out branch name example for a new feature that adds a search bar under ticket #28 would be the following:
feature/28-search-bar
If you are reading this post and suddenly realized your branches are not following any of these rules… don’t panic! Let’s take a look at how you can rename your branches locally and remotely:
To rename your local branch:
# if HEAD is in the branch you want to change
git branch -m [new-name]
# if HEAD is in another branch
git branch -m [old-name] [new-name]
To rename a remote branch:
# Rename your local branch (step above)
# Delete your old remote branch
git push --delete remote branch-name
# Or use this shortcut
git push origin :[old-name]
# Push your new-name branch to remote
git push origin [new-name]
# Reset the upstream branch for the new-name local branch
git push origin -u [new-name]
Clean unused and already merged branches. When you create a merge request, make sure you select the merging option that deletes your branch after merging. Moreover, make sure you exercise good housekeeping by deleting unused branches locally and remotely.
To prune all stale referenced remote branches:
git fetch --prune --all
To delete a branch locally:
# safely - Git prevents you from deleting it if it hasn’t been merged
git branch -d [branch-name]
# force delete
git branch -D [branch-name]
To delete a branch remotely:
git push origin :[old-name]
Commits
Good commit messages matter because they allow you to explain the changes you have made and why when you look back in history or when a team member is reviewing your merge request. Here are some guidelines to compose precise commit messages:
A commit should consist of a single logical change. This one can be hard, especially since it’s very tempting to commit all changes in one commit after several were made. Here is a flag that could help you out:
git add --patch
It will go through all the changes you made, one change at a time, and ask you if you want to commit that specific change.
Keep it short. No more than 50 characters please. If you are modifying or refactoring already existing code, give a short explanation of why you made that change. Not sure what to include in your commit message? Use the following command to see a list of changes in between your working tree:
git diff
Start with a capital letter. And keep it consistent.
No punctuation at the end. It's not necessary.
Start the sentence with a verb. Your commit message should complete the following sentence:
“This commit will…[commit-message]”
Good examples:
“Redirect user to the requested page after login”
“Fix typo in introduction to the user tools”
Are you not happy with your last commit? Use the following command to change it:
git commit --amend -m “New message”
You can also use this command if you want to make a change to your previous commit but want to leave your message intact. For instance, sometimes I forget to remove a log message and I don’t want to create another commit just for that.
git add changed/file.ts
git commit --amend --no-edit
Ignore files
Files that are not required by your project should not be tracked by Git. Understanding what to ignore is beneficial because it will help you keep an unclutter and secure project for you and your team members. Here is a list of common type of files to ignore:
- Operating system files
- Language and framework files
- File downloaded with package managers
- Usernames and passwords
- Debugging logs
Add a local .gitignore
file to the root of your project with the following command:
touch .gitignore
Include any file or folder that you would like Git to ignore on each line. Here are some examples:
# Ignore operating system files
.DS_store
# Ignore SASS config files
.sass-cache
# Ignore npm dependencies folder
/node_modules
# Ignore API credentials
.env
# Ignore all logs
*.log
Note: A DEV community member recommended gitignore.io to generate a .gitignore
file in one step. This tool allows you to enter Operating Systems, IDEs, Programming Language, or Frameworks and it generates a useful .gitignore
file for your project! They also have documentation to help you access their API using your command line.
Did you already commit a file you meant to ignore? It happens to the best of us! Let’s take a look at how to fix it:
First you need to remove the file from your repository. The following command will get Git to stop tracking [file-name], however, the file won’t be deleted from your working system.
git rm --cached [file-name]
Then add it to your .gitignore file and commit this change.
# Ignore [file-name]
[file-name]
Handle large files
Uploading large files to Git is uncommon, however, you could be faced in a situation where you might want to share some large data files with your team members. This could be a problem as cloning, fetching or pulling from a repository that stores large files takes a long time as every version of each large file is downloaded. Don’t cause your team members a headache by doing this, instead share big files through Git LFS (Large File Storage), an open source Git extension. This tool is useful because it replaces large files in your repository with small pointer files. Here are some instructions to use this tool:
-
Download and install Git LFS
git lfs install
-
Track your large files
git lfs track “files/*.csv”
This command will create or update a file called .gitattributes
, which binds tracked file patterns. You will need to commit this file to your repository.
Notes:
- To stop tracking a file with Git LFS, remove it from the
.gitattributes
file. - Cloning and pulling from a Git LFS is the same as using a normal repository.
These are some of the Git guidelines I’ve learned through working with different people in different projects. Everybody has different preferences, however it is important to choose a consistent set of Git rules when collaborating with a team so everybody is on the same page. Let me know in the comments if you have another rule you recommend!
Checkout my previous posts:
Git Explained: The Basics
Git Explained: In-depth Comparison
I explore, define, and explain Git concepts every Saturday!
Top comments (34)
Just wondering why all the
git
commands in the code blocks start with a capital G, yet thetouch
command in them, and thegit
commands in the Handle Large Files section start with lower case...?I write my drafts in a google doc and didn't realize it capitalized those
Git
commands. I updated it! Thank you for pointing that out!Great article, I'll be sharing with my developers! One thing that stuck out though is that there are different philosophies out there for
origin/master
and devs may run into repos where that branch is what is deployed rather than ready to deploy.That is a great point Bryan! I edited my post to include both possibilities. Thank you for the suggestion :)
Love this article and plan to share it with others, but the token naming part has me stuck. I've actually had several issues with other non-git software that interacts with branches that have / in their name. So we name things feature-, bug-, etc instead of feature/, bug/. Jenkins for instance seems to break on the / naming convention and I know I've run into problems in other software too.
That is a really good point Anthony! I've updated this article to suggest any of those name conventions (using
/
or-
) and added a note for the ones that are using Jenkins or other third-party tools in their CI/CD implementations. I'm glad you brought this up as I haven't encountered this issue in the past. Mostly because my team uses Gitlab CI and thankfully/
do not affect our pipelines.I'm glad you enjoyed this article and thanks again for the suggestion!
Thanks for putting it together.
git fetch --prune --all
is a very useful command and it is also possible to automate this process withgit config remote.origin.prune true
It deletes branches when you do a git pull/fetch if they were deleted on the remote.EDIT: Actually I misunderstood the prune command a bit 😅 The prune option will only delete remotely deleted references in your working tree under remotes/* . Your local branches will be kept and you have to still delete them manually with git branch -d.
Or simply
git config --global fetch.prune true
if you want this in all your repos.Nice! I haven't you used that configuration before. I'm excited to try it out :)
Nice article summarizing some good practices!
Also wanted to add there's a newer way to delete a remote branch.
This was added I think because it could be easier to understand and remember.
I'll note though that, at least in my experience, it doesn't let you tab-complete the branch name if you delete the local branch first. But it will if you delete the remote branch before deleting the local one.
However, if you do delete the local branch first, using the other method you mentioned will still let you tab-complete the remote branch name.
Not sure why tab completion doesn't work with the new way of deleting remote branches, but oh well... 🤷♂️
That is a great point, the branch deleting command you added is definitely easier to understand and remember. I added your suggestion to the post, thank you for bringing it up!
In regards to the issues you are having with tab-completing a branch name, I’m not sure why bash git completion does not recognize those two commands as the same, I will look into it and let you know if I find out why this is happening.
Side note, starting on Git v2.8.0 you can use
git push
with the-d
option as an alias from—delete
, in case you like this shortcut better.Thank you again for reading and providing suggestions! :)
Oh neat! That'll be even nicer. :) Thanks!
Another great article Milu! I have a question and a suggestion:
Question: What is
--list
in this line of codegit branch --list “feature/*”
? It looks like it might be the name of the branch. I went back to your earlier article Git Explained: The Basics and didn't notice a naming technique for creating new branches. Whereas, this Atlassian article on branches doesn't use any hyphens to prepend a branch name.Suggestion: I noticed your list of previous posts at the bottom, would you mind being redundant and adding them to the top as well? I'm saving these and having a quick reference as to sequence, above the fold, would be very handy.
Hi Dani!
The command
git branch
orgit branch —list
shows you all the branches you are keeping up with locally. You also have the option to give this command an argument in order to only see a group of branches. For instance, if I followed the token advice mentioned in this article, I should have some branches that start withfeature/name-of-branch
and other that start withbug/
. If I want to only list all the branches that add a feature and ignore all the bug branches, I can give it an argument that asks for all the branches that start withfeature/*
(the asterisk is like a wild card).I hope this explanation helps clarify that command.
Also, thank you for the suggestion, I didn’t know this before you mentioned it but you can do a “series” of posts and they all link to each other at the top of the page. So I took care of that :) Thank you!
Right on! Thanks for the detailed explanation of
git branch
and for making this into a series :)Love that you pulled all these great practices together. Thanks for the reminders and new info!
Thank you for the kind words Zachery! Glad you enjoyed this post :)
Very informative and well written!
Thank you Vishnu!
Thank you for this very informative article on Git. Appreciate it! :)
Thank you for the kind words Hari! I'm glad you found it helpful :)
Really nicely done, thanks for this. The illustrations are beautiful!
Thank you Josh! I really appreciate the encouragement and kind words :)