This is going to sound counterintuitive, but hear me out:
Encourage them to start experimenting with git
One of the interesting things about git is that it's surprisingly easy to make any local operation completely safe. When I first started using git, one of the things I found myself doing was zipping up the entire directory as a back up in case I screwed something up. I later discovered that this is an enormous kludge and is almost never actually necessary to protect your work, but it has the virtue of being very safe and very simple, even if you don't know what in the heck you're doing and how the command you want to try will turn out. The only thing you have to avoid when you're doing this is push
. If you don't push anything, this is a 100% safe way to try out anything you want.
Fear of trying stuff is one of the biggest hindrances to learning git. It gives you so much control over everything that it's kind of daunting. The reality is that you can stick to a few very safe operations for most of your daily use, but finding which commands those are takes some exploring.
By giving them a sense of safety, they'll be far more willing to try to figure out how to do things on their own. And they'll be far more empowered to find a personal work flow on their local machine that works for them. And if not everyone does the same thing locally, that's fine, as long as they adhere to standards with what they push. If it takes zipping up the entire repo before doing an operation to make them feel that way, it's fine; they can pick up on better ways of doing things as they go and as they try stuff. Anything to get yourself to start trying stuff and seeing what it does.
This doesn't mean training is worthless. On the contrary, training can help introduce you to features and patterns and norms. But it isn't a replacement for sitting down and actually doing stuff in your daily work. Neither git nor SVN are things that you can just go to a class and then you know everything about. You have to use them to solve your problems to get familiar with them and which features are well suited for which problems.
Stop discouraging them from learning the ins and outs of git
I mentioned not pushing anything, which actually goes against one of the things you've been teaching them: to always "Commit & Push". I believe you should stop telling them to do this and tell them to start doing the opposite. Git has basically 5 "places" where your changes can be:
- On disk, uncommitted
- Staged but not committed
- In a local commit
- In a local stash
- Remote repositories (Only commits and tags are ever pushed and pulled between different repositories)
Instead of encouraging them to pull and push everything in a single step, encourage them to leverage these 5 different places. Encourage them to:
This will encourage them to check their work before it's made publicly available to everyone, which means they'll catch their mistakes sooner. They'll see the commit and think, "Wait, that's not what I wanted," and unlike in SVN, they can go back and try again before they push.
Once they get used to the idea of understanding where their changes are, then they can start deciding when to skip steps and combine certain operations (when to pull because you already know you want fetch+merge or when to click that Commit & Push option).
This is actually one of the enormous benefits of git over SVN, and git is designed with this usage pattern in mind. SVN, by contrast, assumes a central repository, so it's unsurprising if the tooling for git isn't as optimized for the same workflow. In SVN, if your commit is wrong, your only real recourse is a new commit to undo the mistake.
Doing this will actually naturally lead to the next strategy:
Encourage them to use local branches
Local branches actually ease a lot of the pain points of working on shared files. I can make all the changes I want in my own branch, and it will never affect anyone since I'm not pushing them. Then when the time comes, I can use all of the same merge and rebase strategies, only easier:
- I can rebase my local branch, which makes merging it into master trivial.
- I could use a plain merge (create a new commit) in master to bring my local branch's changes into it.
- I can squash merge my entire local branch into a single commit on master if I think my branch is too much of a mess to salvage.
Using local branches is also a good start to figuring out a systematic branching strategy. It helps your users understand their own branching needs better, so you can choose a strategy based on needs and the team's current understanding/skill level and not just drop in Gitflow because everyone has heard of it.
Summary
In brief, git is not SVN and cannot be treated like it. You need to:
- Eliminate the fear by encouraging safe experimentation.
- Help them understand how git is different so they can see how that changes their normal workflow.
- Help them understand the features available to help them solve their problems more easily.
This will all help you gradually adopt better git usage, until you reach the point where you can start implementing a set of standards.
Specific features
In the immediate term, the following ideas might help.
Rebase
You mentioned rebase and that you don't really understand it in your question. So here's my advice: try out what I just described. Make some changes locally while someone else pushes some changes. Commit your changes locally. Zip up your repository directory as a back up. Fetch the other person's changes. Now try running a rebase command and see what happens to your commits! You can read endless blog posts or receive training about rebase and how you should or shouldn't use it, but none of that is a replacement for seeing it live in action. So try it out.
merge.ff=only
This one is going to be a matter of personal taste, but I'm going to recommend it at least temporarily since you've mentioned you already have trouble with conflict handling. I recommend setting merge.ff
to only
:
git config --global merge.ff only
"ff" stands for "fast forward." A fast forward merge is when git doesn't need to combine changes from different commits. It just moves the branch's pointer up to a new commit along a straight line in the graph.
What this does in practice is prevent git from ever automatically trying to create merge commits. So if I commit something locally and then pull someone else's changes, instead of trying to create a merge commit (and potentially forcing the user to deal with conflicts), the merge will just fail. In effect, git will have only performed a fetch
. When you have no local commits, the merge proceeds normally.
This gives users users a chance to review the different commits before attempting to merge them and forces them to make a decision about how to best handle combining them. I can rebase, go ahead with the merge (using git merge --no-ff
to bypass the configuration), or I can even just put off merging my changes for now and handle it later. I think this small speed bump will help your team avoid making the wrong decisions about merges. You can let your team turn it off once they get better at handling merges.