18

I am starting to learn Git. I've been messing around with GitKraken, and I hope that using a GUI is a viable path for saving and sharing stuff. I prefer GUIs to the command line.

Now I understand, in the GUI, I need to stage files, then commit them and then push, to upload them. But why are push and commit two different things? Why would want to just commit locally, without the following upload to keep files synced?

Matt Messersmith
  • 12,939
  • 6
  • 51
  • 52
marko-36
  • 1,309
  • 3
  • 23
  • 38
  • 5
    Since you wouldn't use something so old as a CLI, you might not be able to imagine this: offline work – fredrik Aug 12 '18 at 12:41
  • Haha, I am quite familiar with offline work. I can even handle stuff like an axe or hammer. :) But seriously, services and apps which dismiss a possible GUI or at least pluto it, and force mortals into mispeling in a CLI are run by nerds who just want to feel hardcore, old-school and special for not utilizing visual memory. This, is my personal opinion, since I got stuff to do, life to live. :) – marko-36 Aug 12 '18 at 12:50
  • 4
    [Why learn git when there are GUI apps for Git?](https://softwareengineering.stackexchange.com/q/173297/2762) – poke Aug 12 '18 at 12:56
  • If you have stuff to do, then learn the CLI. It has nothing to do with feeling hardcore: it's legitimately more productive/faster. In the short term, learning the CLI will be less productive than the GUI, but after you learn your CLI, the new-found productivity will pay for itself in no time. GUIs are *always* slower than a half-competent CLI user who minimally understands how to create scripts/aliases. – Matt Messersmith Aug 12 '18 at 13:01
  • 3
    Don't dismiss command-line interfaces out of hand. There are good reasons that many strong developers, even young ones, choose to use them in 2018. It's usually best to approach unfamiliar things with an open mind; unfortunately you appear to be doing the exact opposite of that. (As a side note, Git itself was created in 2005. It's quite a modern tool, despite its interface.) (As _another_ side note, Vim and related editors _don't_ need you to press `i` for them even to respond. Its other mode—command mode—is where a lot of the magic happens. It's just that you're not typing into a buffer.) – ChrisGPT was on strike Aug 12 '18 at 16:01
  • I vote to close this question because it contains a clear flame-bait. – kostix Aug 13 '18 at 14:23
  • 1
    @kostix The question is fine I think, minus the CLI flame (which has been removed). I thought about voting to close at first, too, but I've been asked this question many times by coworkers who are new to git. It might be nice for me to just point them to this in the future since there are 3 good answers here. – Matt Messersmith Aug 13 '18 at 14:57
  • Learn Git at the command line, not in a GUI: https://www.youtube.com/watch?v=1mJQdcDi7z0&time_continue=2m – jub0bs Sep 26 '18 at 18:06
  • @Marko36 imagine trusting a GUI over a CLI – Emobe Dec 03 '19 at 09:17

4 Answers4

40

A couple of (concrete) reasons. TLDR in bold.

The first reason is you might not be able to push to the remote, because you aren't connected to the internet.

The second reason is that sometimes commits aren't ready to be pushed. For example, I practice TDD. After I commit a failing test (which I do), I don't want to push that to the remote, because then my team may pull in a failing test suite. Another common practice is to squash these commits before pushing them out so it looks like the feature was one single commit.

Third reason is that it's a personal project that you don't want to share with anyone, and so there is no remote to push to at all. You don't have to have a remote with a git repo.

Fourth reason is you may have multiple remotes (in general, distributed semantics get in the way). So after you commit, how would git know which remote you want to push to? All of them? A certain one? A certain two out of the seven? Pushing must be explicit from git's perspective due to the semantics of git being a distributed VCS. See poke's answer for more detail.

P.S. This is off topic to the question, but the command line shells (including bash) are extremely powerful interfaces once you learn to use them. After you become proficient with these tools, using them is much faster than any GUI you're going to find. This has to do with the fact that you can do powerful actions with keystrokes instead of the mouse, and that it's infinitely customizable to fit your needs.

Matt Messersmith
  • 12,939
  • 6
  • 51
  • 52
  • So commiting changes without pushing allow the save-load behaviour done locally during development. Once you are happy with your work, you then commit AND push. Is that correct? What is "squashing commits" I googled and I understand it means merging commits? Thanks. – marko-36 Aug 12 '18 at 13:00
  • Note that this answer focuses primarily on the possible use cases you gain from this separation, e.g. preparing the commits before actually sharing them. But there are also technical requirements due to the distributed nature of Git. – poke Aug 12 '18 at 13:01
  • 2
    @Marko36 Yes, you've basically got it. Once you're happy with the "new" state that everyone will see, then you can push your work. This may or may not be after a single commit. Squashing commits just means turning a stack of commits into a single commit. So if I have 10 commits, I might not want everyone to see the 10 commits I made. Maybe I was swearing in the commit log, or some of the commits wouldn't make sense to revert to (like a failing test commit). So, instead, you squash the commits into 1 commit (locally), and then push that single commit (same content as the 10 commits). – Matt Messersmith Aug 12 '18 at 13:04
  • @poke Good observation, I've updated with another concrete example (use case), but tried to allude to a more abstract reason about distributed semantics...hopefully that scratches your itch. – Matt Messersmith Aug 12 '18 at 13:09
  • 1
    @MattMessersmith Yup, that works for me. Btw. my comment wasn’t meant as criticism but rather just to point out the focus of your answer. I think our two answers make a good pair since I focused completely on the technical aspect while you covered the use cases :) – poke Aug 12 '18 at 13:12
8

Git is a distributed version control system. As such, there is no single central repository, like with Subversion or even CVS. So if there was a single command to commit and push, then where would that commit would go? What would be the remote repository?

In Git, there is no central repository. There is not even any hierarchy in repositories. For a local repository, any other repository is a remote repository it can interact with. And the local repository is just a possible remote repository for any other repository.

So local and remote are just points of view relative to your current location: The local repository is always the current repository, and every other repository is a remote that you can interact with.

When working with Git, your local repository is what you interact with: You commit all your changes locally. This has many benefits and use cases that I won’t go into detail here, but essentially it is what makes version control distributed, as the local repository has all the information, the full history.

So when you have that local repository, which has the full history and all the changes, you need a way to interact with other repositories, in order to allow you to share the history. The two ways to do that are push and pull (or fetch). Since with distributed repositories, every repository is the same, every repository can push or pull from another (assuming they have access).

In the end, committing and pushing is required to be separate steps because one is interacting with the (local) repository while the other is a deliberate step to share changes with a remote repository.

poke
  • 369,085
  • 72
  • 557
  • 602
6

Another answer: there isn't a good reason

In the old days (like five years ago--ancient history by today's standards of memory) people were sometimes not connected to the internet! And they wanted to continue working! So they just committed as they worked. When connection was achieved, they'd go ahead and push all their commits. Git was designed with this as the primary paradigm.

Flash-forward all those eras to the present and lo, the mechanics of versioning our software hasn't changed (much).

Some people have argued that you keep all your commits local until you're satisfied that your code is robust. I admire their instincts: protect the main repository code; keep it as flawless as possible. Yes, of course, please do!

But Git provides a mechanism that works much better for not-so-perfect-code, it's called branches. Make a branch, work on it (pushing commits all along) until satisfied, then merge that branch to the main. This way if something happens to your computer (hard drive crash, coffee spill, theft, etc.) all your work is still backed up. That's one of the points of version control, right?

Yet others have argued that in a highly distributed development system, one needs to specify where and how to push commits. This is certainly an option, but I have yet to see this in practice. I can't imagine a company saying to its developers, "Go out there and each of you keep your own copy of the code. We'll let you push and pull from each other as you feel and hope that nothing goes wrong or gets confusing." Yeah. So much easier to setup a bitbucket or github account and tell everyone: "Use this as your origin!"

So to be blunt: just push with every commit. There is no downside to do this, and there's some small chance of losing work if you don't.

SMBiggs
  • 11,034
  • 6
  • 68
  • 83
3

They serve different purposes. Each commit should change one isolated aspect of the code; for example, rename a variable, replace calls to one function with calls to another, or even just fix a typo in a comment. Think of them as rollback points; if I change my mind about the approach I took here, can I drop a small set of commits and still keep these other, unrelated changes?

A push should only happen when your series of commits reaches a new stable point in development which has been tested enough to be shared with your colleagues or collaborators.

It's not impossible or unusual to make one push for each commit if you are working e.g. on fixing minor bugs. But a lot of the time, it makes sense to commit individual changes as you proceed towards a larger goal, and only push when you think you have reached that goal.

tripleee
  • 175,061
  • 34
  • 275
  • 318