I agree with the author that learning and becoming handy with git cli is very important.
I don't agree that you should stop using a GUI for git, especially if you've already cut your teeth on the command line. Tower, a git GUI for Mac OS X, has a great interface and ties in very well with the core git functionality. I've learned a lot about stashing, merge conflict resolution, and cherry-picking, thanks to that app. Also, Tower shows a tree graph, similar to the network diagram the author "seriously cannot live without."
Why knock visual tools when when you rely on them so much?
I used git at the command line for two years before trying (and later buying) Tower.
I am a very visual person. It gives me greater confidence in what I'm doing when I can see a polished visual overview, it makes me more willing to use powerful features like picking individual lines to commit, to avoid any single commit containing a mixture of use cases.
But I always make sure I know what the GUI is doing on the command line before trusting it to be doing the right thing. I made sure I understood rebasing correctly before setting it to be the default pull behaviour in Tower. Similarly, I never feel comfortable using a one-line deployment script before running through a deployment by hand first.
Any tool that makes our lives easier and less likely to make silly screwups is a good thing in my eyes. It doesn't matter whether that tool is a GUI or a script. I prefer using a GUI for databases too, because the command line is woefully inadequate at letting me grasp the shape of data quickly.
I've tried a number of gui tools for git but I keep coming back to the command line. You can format your `git log` output to give you your network graph and `git add -[pi]` allow me to stage hunks of diffs much like a GUI tool might.
I think more than what tools you use (gui or command line) it's really useful to get an understanding of gits internal model. It informs day-to-day use and is a great example of an elegant, well-designed system.
The omglog gem is also useful for working with git. It gives you a graphical log of the entire repo (not just your current branch as a normal git log does), and it auto updates by monitoring for file system changes (OSX only).
To install:
sudo gem install omglog
Then just run `omglog` in the root of your repo, or use this alias in your `.gitconfig` to automatically run it from the root of whatever repo you're in:
[alias]
omg = !omglog
(shell commands, starting with a "!" command in a git alias are always run from the root of a repository)
Isn't it a little ambitious to call yourself a veteran $foo programmer when you've been doing it for a little over a year?
Particularly when the blog post before this is discussing how .m and .h files totally confused you. God help him if he gets asked a linked list question in an interview.
The OP gives his own definition for rebase: git rebasing is taking all your local changes since the last push and put them ahead of other people’s changes regardless of the date you made the commit.
But fails to explain _why_ you'd want to do that. Can anyone fill in that why for me?
My understanding is that it keeps the history cleaner at the expense of being "historically correct". It's cleaner because you have fewer merge commits, but less historically correct because it makes your commits look like they happened after the commits pulled in by rebase.
Personally, I use merge (with --no-ff) vs. rebase. The only time I actually use rebase is to squash a series of (unpushed!) commits on a feature branch, and I usually only do that if I went hog-wild, committing more than necessary while experimenting.
It keeps the upstream history cleaner at the expense of being locally historically correct. In my opinion the nice thing about having everyone rebase onto upstream is that when their changes get merged into upstream, upstream's history shows an accurate linear representation of when a piece of code was accepted into upstream, which to me is far more important than having an accurate local history.
Great point. One of the more confusing things about looking at the upstream logs when not using rebase is that they are (by default) in chronological order. It does seem like it would be more useful to have commits upstream show in the order they were merged in.
master on your local repo is a different reference to master at origin and master at other developers machines. By merging your master into origin/master instead of rebasing, you leave the history looking like multiple branches were merged together.
By rebasing onto origin/master instead of merging, you leave the history looking linear.
Ultimately it's about aesthetics, you don't gain anything by rebasing (when pulling) other than a cleaner history.
I'm not certain this is due to the particulars of the workflow of the team I was working with, but one of the benefits I saw of rebasing over regular merging was that rebasing let us resolve conflicts at the point of the commit in which they emerged, rather than in a merge commit at the end.
When I'm working on a branch and I want to pull changes from master into my branch so that I'm working on the latest code base I do
> git rebase master
What this does is that it temporarily reverts all my changes on this branch, applies all the changes from master on my branch and then reapplies my changes on this branch.
I really should go back and start making new blog posts... I'd dropped the ball because I ended up on a few enterprise SCM (software configuration management) gigs shortly after.
I think the best thing I did for my team is explain them how branches work, and how not-so-special are they, branches are just pointers to a commit, and commits are never 'lost'.
Branching can often be a good strategy if you have a large team and you don't want large uncompleted chunks of work to block quick fixes & deploys, etc. The situation you want to avoid is:
1. Engineers A & B are working on a medium-sized story that's not really done yet, but is in master anyway
2. Somebody discovers a small but critical bug in production
3. Engineer C can write a bugfix very soon, but can't deploy it to production because the other story isn't done yet.
But if your team never ends up saying "I'd deploy that but master isn't clean right now due to different changes", you probably just don't need to branch that much. Maybe your team is smallish or maybe you're capable of always breaking up work into really small increments. It really depends on everybody's situation.
Branching is more overhead in some circumstances but I've also found they can make things much easier. But I also wish that more people were comparing strategies and trade-offs because this stuff gets subtle and there are really lots of ways to do it.
We faced this situation before. What we do is:
- When there is a feature that is not done yet, but has some user-facing code, we use feature toggler to disable it on production
- we deploy quick fix by doing a cherry-pick
We discussed about branching a while ago to solve this problem more effectively but still not satisfied with the pros vs cons. For us, branching only makes sense if we switch to use branching completely, and thats quite a big change.
Yeah, personally I know a number of solid devs who like feature toggling but the notion has always rubbed me the wrong way. Especially because half the time I'm adding a non-trivial feature, I'm always semi-refactoring the code underneath to deal with the common patterns and concepts that emerge as a result of that addition. But I'm a big refactoring-as-you-go kind of person--I don't know how common this is.
Branching is definitely a significant investment for a team. It's best done when you've got somebody in-house who can guide everybody through the etiquette and how to use git to best support it. And if you want to do it all the way then you want to support in multiple places in your development stack -- QA servers, staging servers, CI, etc.
But for large units of work that genuinely should stay out of master -- large user-flow rewrites, big code refactorings or database migrations -- I find it a great way to have significant experimentation off to the side and then bring it back into master when it's ready for prime-time.
this was a question I had - how do you have your QA,testing,staging setup to test branches ? Or is fast and frequent commits (by design) eliminate the need for the commit-deploy-test cycle and replace it with a review step instead ?
Generally speaking I like to have at least one CI environment available for every branch that makes you nervous, plus master. So what number you're dealing with depends on the team. Sometimes you have eight engineers but only four of them are doing something major at any given time.
Of course, whatever you call what you deploy to production -- master, production, timestamp tagging, etc -- it should ideally pass CI before getting deployed as well. And there are merge conflicts to deal with, too -- that ideally belongs to whoever's doing branching.
So, maybe my ideal workflow looks like this:
* Branch away from master
* As you work in your branch, grab a CI server if you feel like it (telling
everyone else)
* Commit code in your branch, keeping an eye on your CI as you go
* Periodically merge in from master, dealing with merge conflicts in your branch,
*not* in master
* When you feel like it's ready to go, get whatever review you feel like you
need -- code review, product manager review, etc
* If you feel 99% certain it's good, merge it into master and push that back to
origin
* Wait for master CI to pass
* Deploy to production
* Beer
From an etiquette point of view, there are things that can go wrong, not least the individual commitment to deal with merge conflicts before they get involved in master. And conflict resolution cannot be rushed. If you have engineers who are just gonna edit files randomly to get git to accept their merge, you're going to have problems. (But if you have those sorts of engineers, you already have problems.)
Out of curiosity, do you work for a relatively small company? I ask because I can't imagine this scaling particularly well, with production code containing a large number of "dead" code paths that you have to cross reference with your feature toggler to check on their status.
Do you feel like you gain anything significant from your method (apart from the simpler git interaction from having just one developer branch)?
A local git branch is super-cheap, so there's hardly any downside to using them. The upside, even for a single developer, is the ability to work on multiple features/bugfixes simultaneously, and merge them into master only when they're ready.
Where I work, there are several different git styles, but they all work nicely together if everyone adheres to one simple rule. I'm going to say it loudly, because it's important:
origin/master must be deployable.
If that means developing in a branch, fine. If that means accumulating several patches locally in master that you haven't pushed yet because you're not done, fine. Just make sure that origin/master can always be deployed to the servers.
Actually, come to think of it, both of those things are pretty much equivalent to using branches for anything non-trivial.
Can somebody explain how rebasing affects shared histories. Say I'm rebasing a feature branch that's shared via github, will rewriting the commit history prevent me from pushing?
I avoid `git commit --amend` because of that, and thought that `rebase` had the same problem. So for that reason, I always use `merge`. Am I mistaken?
No, you are absolutely right. History rewriting is fine if you do it on a private branch, but on shared branches it can be problematic.
If there are updated refs on a shared branch, you need to use the --force flag when pushing, overwriting the previous refs. All the other people pulling will also need to use the --force flag to get their refs updated.
It could also lead to data loss on all the repositories that do this if something goes wrong. And it forces other team members to use the correct flag when pulling and otherwise dealing with cryptic error messages when they don't do this.
--amend is fine if you haven't pushed yet, otherwise it has the same problems as rebase for shared stuff.
I love git. It helps me to wake up in the morning some days. But...
The OP's attempt to visualize git concepts falls quite short. This same old branching graph does little to nothing to illustrate these concepts. I cannot tell you how many friends and colleagues threw up their hands when someone tries to graph it out these way.
The merge-often strategy that the OP recommend in his post is the one that is Linus abhors so much. He even calls it "unholy mess" : https://lkml.org/lkml/2012/1/10/267. Basically that merge strategy can produce pointless merges.
The strategy isn't the issue. It's whether it fits with the process you've set up.
If you do code-review on the contributions/pull requests then I can see where the merge-often strategy causes issues. The auto-generated merge commits don't give you the context of the updates that are pulled in and will lead to having to spend time going back through the commit tree. It may not lead to the introduction of issues or regressions but you can't be sure.
However, if you're set up as a small team with good internal communication or a high level of trust, then merge-often can be a good thing in that you usually aren't left with big merge issues to deal with and you're more likely to have any conflicting updates fresh in your mind.
We solve the problem with rebasing. If it's not part of the main branch then it's not part of history, so rebasing to organize the pull request makes sense.
Rebase works great when you need/want to preserve he revision history. It's probably the ideal process to put in place if you can mandate it.
One thing to keep in mind is that it might lead to a number of merge conflicts that may be difficult or tedious to resolve depending of how the branches have diverged. Merging may avoid these.
His opinions on not rebasing onto master and instead merging are his own. Personally I find merging far more confusing in terms of understanding history graphs and always rebase before issuing a pull request. I think you will find that generally a lot of open source projects on Github have this practice of asking people to "please rebase your changes onto master so I can merge".
One practical reason is when doing bisects.
There are certainly two schools of thought on this, but "this is confusing to me so don't do it" shouldn't be considered a valid opinion.
I don't agree that you should stop using a GUI for git, especially if you've already cut your teeth on the command line. Tower, a git GUI for Mac OS X, has a great interface and ties in very well with the core git functionality. I've learned a lot about stashing, merge conflict resolution, and cherry-picking, thanks to that app. Also, Tower shows a tree graph, similar to the network diagram the author "seriously cannot live without."
Why knock visual tools when when you rely on them so much?