Git is a very very powerful tool which is often quite difficult for even experienced programmers to wrap their heads around. To get started, we have to define the terms branch, repository, and remote and draw clear differences between them:
A git branch is a collection of commits (a.k.a changes). Branches are named based upon their role in the project. Github uses the name master as the branch you make commits on that are considered "the good to go" commits.
A git repository is a place you store your branches.
A git remote is the name for a repository that isn't on your computer. Heroku and Github both provide remotes for different purposes; Github uses them to collaborate on writing more code; and Heroku uses them so you can deploy code to a particular application environment.
Let's pretend you have the following:
A local repository where you commit changes directly to master. We'll call this local for now.
A Github repository which we will call origin;
A Heroku application which we will call staging;
A Heroku application which we will call production
We're also going to assume that you're not using Heroku pipelines to automatically deploy pushes to Github; not because it's a bad idea to do that, but because that won't help you understand how to use the git command line program to manipulate the projects .git/config to push your changes to github/origin, heroku/staging and heroku/production.
We're going to start with a blank git config, execute a git command, and review the resulting git config.
So! LET'S GET STARTED!
First, run git clone git@github.com:your-git-username/your-project.git
First, the weird-looking [a-word] syntax. This is similar to the ini file format and is how git groups configuration for a particular topic. the [core] config includes a bunch of things we're going to mostly ignore for now. That said, if you want to find out what each of those mean you run the terminal command man git-config to open the manual for git-config and then use the / key to enter "search" mode and typing core\. to jump to the first reference for what you can set as part of git's core config. You can tap n to cycle through the rest of these items.
So let's look at the [remote "origin"] section! This has two configuration settings by default: the url and the fetch options. The url configuration specifies where the remote named origin lives. As you can see, the url here is currently hosted on the github.com domain. The fetch configuration is used to configure how the git fetch and git pull commands handle retrieving information from the origin remote. You can use the same fancy-pants man git-config and /remote\. plus hammering that n key to skim what each of the options are for the remote configuration.
Right now, if you were to run git branch -a you will see that you have ~3 entries!
The one prefixed with an * is the current locally checked out branch, while the ones prefixed by remotes/origin/ are letting you know that the origin remote has a branch named master and that the origin/master branch is the primary branch for the origin remote.
Next, we'll look at the [branch "master"] section. This also has two configuration settings when you initially clone the repository. The first one, remote specifies which remote git push and git fetch and git pull will use for the master branch by default. This allows you to run git push without any arguments and be confident that the commits in the master branch will go to the origin remote (AKA github). You may also explicitly use these defaults by running git push origin master instead of git push. I'm an old curmudgeon who dislikes implicit things and convenience, so I tend to rungit push origin master (and the corresponding git pull origin master) more often than I run git push.
The merge configuration says that "when pulling I want to merge the changes from the origin/master branch into my local master branch; and when pushing I want to merge the changes from my local master branch into the remoteorigin's master branch.
PHEW That's everything that I expect to be in your .git/config from initial clone. Now on to the next step: What about when you add your heroku environments!
Using what we've learned, we know we want to create a remote that corresponds to the application named staging on heroku. The syntax for doing so is: git remote add staging https://git.heroku.com/staging.git (As an aside, you will need to change the url to what your Heroku application says the url should be).
Now let's look at the additions to our .git/config file:
Everything else should stay the same at this point; and both of the configuration options should look familiar, as they are the same options that are set on initial clone. If you were to run git branch -a you may expect to see a remotes/staging/master entry... but wait! It's not there!?
That's because adding a remote doesn't automatically provide your local computer with any information about the remote beyond that it exists. If you run git fetch --all git will reach out to both your origin and your staging remotes and update it's local cache with information about which branches the staging remote has.
Now if you run git branch -a you will see an entry for remotes/staging/master.
So, we've now updated our git config with a remote named staging that points to the heroku app we have named staging; but we're not done yet! Now we need to push all the code we have in our local master branch onto the staging heroku app. I bet you can guess exactly what we need to type to do so!
If you saidgit push staging master then congratulations! You're 100% correct! If you said anything else, then still congratulations because git is confusing and complex and you've tolerated my ramblings long enough to get here.
Next, we repeat for our production heroku app: git remote add production https://git.heroku.com/production.git which adds the following lines to our .git/config
And, once again, to push the code we have locally into the heroku remote; we run git push production master. (We don't have to run git fetch --all or git branch -a, but they are useful for getting bearings and illustrative purposes.
So, there we go; we have 3 remotes in our git config, our master branch is set to push to origin by default, and we can use git push <remote> master to merge our local master branch into our production and staging Heroku application remotes..
FINALLY! WOOOOOOOOOOOoooooooooooooo!
Now we get to enter CHALLENGE MODE! How can we unwind your .git/config so that it matches the .git/config you want?
Now, I'm not 100% certain what the name of the app you are building on Heroku is, so I'm going to pretend the name is jess-is-an-awesome-programmer and that is the name that is used on both github for the repository and on heroku for production.For the staging heroku app I'm going to pretend it's jess-is-an-awesome-programmer-staging
First, we're going to create a remote named origin that points to your github repository:
Third, we're going to remove all the Heroku remotes, because it's often easier to make these kind of changes when there isn't anything dangling from previous attempts:
git remote rm staging
git remote rm production
git remote rm heroku
Run cat .git/config between each of these to see how it changes! (OK I'll tell you, it removes the parts labeled [remote "staging"], [remote "production"] and [remote "heroku"].
git remote add production https://git.heroku.com/jess-is-an-awesome-programmer.git
cat .git/config (yay! three more added lines!)
Now, if you run git push origin master (or git push) your commits on your local master branch will be on github. When you run git push production master your commits on your local master branch will be on the jess-is-an-awesome-programmer application and so on.
Keep in mind that changing the .git/config by. hand can leave your git program in a slightly broken state. So be careful if you do change it by hand!
Hey Jess!
Git is a very very powerful tool which is often quite difficult for even experienced programmers to wrap their heads around. To get started, we have to define the terms
branch,repository, andremoteand draw clear differences between them:A git branch is a collection of commits (a.k.a changes). Branches are named based upon their role in the project. Github uses the name
masteras the branch you make commits on that are considered "the good to go" commits.A git repository is a place you store your branches.
A git
remoteis the name for a repository that isn't on your computer. Heroku and Github both provide remotes for different purposes; Github uses them to collaborate on writing more code; and Heroku uses them so you can deploy code to a particular application environment.Let's pretend you have the following:
master. We'll call thislocalfor now.origin;staging;productionWe're also going to assume that you're not using Heroku pipelines to automatically deploy pushes to Github; not because it's a bad idea to do that, but because that won't help you understand how to use the
gitcommand line program to manipulate the projects.git/configto push your changes togithub/origin,heroku/stagingandheroku/production.We're going to start with a blank git config, execute a git command, and review the resulting git config.
So! LET'S GET STARTED!
First, run
git clone git@github.com:your-git-username/your-project.gitThen, run
cat .git/config:Let's break this down, shall we?
First, the weird-looking
[a-word]syntax. This is similar to the ini file format and is how git groups configuration for a particular topic. the[core]config includes a bunch of things we're going to mostly ignore for now. That said, if you want to find out what each of those mean you run the terminal commandman git-configto open the manual forgit-configand then use the/key to enter "search" mode and typingcore\.to jump to the first reference for what you can set as part of git'scoreconfig. You can tapnto cycle through the rest of these items.So let's look at the
[remote "origin"]section! This has two configuration settings by default: theurland thefetchoptions. Theurlconfiguration specifies where the remote namedoriginlives. As you can see, the url here is currently hosted on thegithub.comdomain. Thefetchconfiguration is used to configure how thegit fetchandgit pullcommands handle retrieving information from theoriginremote. You can use the same fancy-pantsman git-configand/remote\.plus hammering thatnkey to skim what each of the options are for theremoteconfiguration.Right now, if you were to run
git branch -ayou will see that you have ~3 entries!The one prefixed with an
*is the current locally checked out branch, while the ones prefixed byremotes/origin/are letting you know that theoriginremote has a branch namedmasterand that theorigin/masterbranch is the primary branch for theoriginremote.Next, we'll look at the
[branch "master"]section. This also has two configuration settings when you initially clone the repository. The first one,remotespecifies which remotegit pushandgit fetchandgit pullwill use for the master branch by default. This allows you to rungit pushwithout any arguments and be confident that the commits in themasterbranch will go to theoriginremote (AKA github). You may also explicitly use these defaults by runninggit push origin masterinstead ofgit push. I'm an old curmudgeon who dislikes implicit things and convenience, so I tend to rungit push origin master(and the correspondinggit pull origin master) more often than I rungit push.The
mergeconfiguration says that "when pulling I want to merge the changes from theorigin/masterbranch into my localmasterbranch; and when pushing I want to merge the changes from my localmasterbranch into the remoteorigin'smasterbranch.PHEW That's everything that I expect to be in your
.git/configfrom initial clone. Now on to the next step: What about when you add your heroku environments!Using what we've learned, we know we want to create a remote that corresponds to the application named
stagingon heroku. The syntax for doing so is:git remote add staging https://git.heroku.com/staging.git(As an aside, you will need to change the url to what your Heroku application says the url should be).Now let's look at the additions to our
.git/configfile:Everything else should stay the same at this point; and both of the configuration options should look familiar, as they are the same options that are set on initial clone. If you were to run
git branch -ayou may expect to see aremotes/staging/masterentry... but wait! It's not there!?That's because adding a remote doesn't automatically provide your local computer with any information about the remote beyond that it exists. If you run
git fetch --allgit will reach out to both youroriginand yourstagingremotes and update it's local cache with information about which branches thestagingremote has.Now if you run
git branch -ayou will see an entry forremotes/staging/master.So, we've now updated our git config with a remote named
stagingthat points to the heroku app we have namedstaging; but we're not done yet! Now we need to push all the code we have in our local master branch onto thestagingheroku app. I bet you can guess exactly what we need to type to do so!If you said
git push staging masterthen congratulations! You're 100% correct! If you said anything else, then still congratulations because git is confusing and complex and you've tolerated my ramblings long enough to get here.Next, we repeat for our
productionheroku app:git remote add production https://git.heroku.com/production.gitwhich adds the following lines to our.git/configAnd, once again, to push the code we have locally into the heroku remote; we run
git push production master. (We don't have to rungit fetch --allorgit branch -a, but they are useful for getting bearings and illustrative purposes.So, there we go; we have 3 remotes in our git config, our
masterbranch is set to push tooriginby default, and we can usegit push <remote> masterto merge our localmasterbranch into ourproductionandstagingHeroku application remotes..FINALLY! WOOOOOOOOOOOoooooooooooooo!
Now we get to enter CHALLENGE MODE! How can we unwind your
.git/configso that it matches the.git/configyou want?Now, I'm not 100% certain what the name of the app you are building on Heroku is, so I'm going to pretend the name is
jess-is-an-awesome-programmerand that is the name that is used on both github for the repository and on heroku for production.For the staging heroku app I'm going to pretend it'sjess-is-an-awesome-programmer-stagingFirst, we're going to create a remote named
originthat points to your github repository:git remote add origin git@github.com:monkeywithacupcake/jess-is-an-awesome-programmer.gitSecond, we're going to make sure
masteris set up to default pushes to your remote namedorigin, instead of the one namedproductiongit branch --set-upstream-to remotes/origin/masterWhen you run
cat .git/configand you after this, you'll see that the section that configured yourmasterbranch now reads as follows:Third, we're going to remove all the Heroku remotes, because it's often easier to make these kind of changes when there isn't anything dangling from previous attempts:
git remote rm staginggit remote rm productiongit remote rm herokuRun
cat .git/configbetween each of these to see how it changes! (OK I'll tell you, it removes the parts labeled[remote "staging"],[remote "production"]and[remote "heroku"].Finally, we re-add those remotes:
git remote add staging https://git.heroku.com/jess-is-an-awesome-programmer-staging.gitcat .git/config(to see the added lines!)git remote add production https://git.heroku.com/jess-is-an-awesome-programmer.gitcat .git/config(yay! three more added lines!)Now, if you run
git push origin master(orgit push) your commits on your local master branch will be on github. When you rungit push production masteryour commits on your local master branch will be on thejess-is-an-awesome-programmerapplication and so on.Keep in mind that changing the
.git/configby. hand can leave yourgitprogram in a slightly broken state. So be careful if you do change it by hand!Good luck Jess!
Zee
Thank you for breaking this down for me. Awesomely detailed and helping me understand.
You deserve a sticker!!!