-
Notifications
You must be signed in to change notification settings - Fork 1
Using Git
- Safeguard the CNAME and Secondary Config Files
- Keeping Up-To-Date
- Branching
- Solving Merge Conflicts
- Dealing With Rebases
This guide contains essential information about how to use Git when working on the site.
As mentioned elsewhere, it's essential to run git update-index --skip-worktree CNAME when you first set up the repo. Not doing so will cause havoc between the staging and production sites.
If you're uncertain whether you've set this or not, you should run git ls-files -v | grep ^S. If the output shows Shows S CNAME then you're ok. If not, then absolutely run git update-index --skip-worktree CNAME before doing anything else
- Always run
git fetch --allbefore doing any local work. This fetches a record of any changes that other people made to the online repo. Most of the time you'll then be able to rungit pullorgit pull alland immediately incorporate the changes. Sometimes you may run into merge conflicts (i.e. both you and the online repo updated or added the same file(s). Merge conflicts are a headache. See the Solving Merge Conflicts and Git Diff sections below.
Note: If you forget to do a fetch and pull at the very beginning of your work, then you're basically asking for merge conflicts to happen.any of the following will most likely happen:
Note: this section is in-progress and may be in need of some updates.
If you're making more complex edits (say updating layouts or scss files), then your best bet is to create and work off of a branch. Follow the procedure below:
- Type
git branchto view whatever current branches are on your local repo - Type
git branch some_nameto make a new branch - Type
git checkout branch_nameto switch to the branch - Make your changes.
From here there are two routes:
- Update via a pull request
Type git push origin branch_name to push your branch to the remote repo. Then create a pull request for whoever's maintaining the repo to approve and merge your files. For an overview on pull requests, see here
- Merge the branches locally and then push to the remote repo.
Steps:
- Type
git checkout masterto return to the main branch - Run
git pull origin masterto get the latest changes from the online repo - Type
git merge branch_name - If there were no merge conflicts, then you can push to the remote repo via
git push origin master. Otherwise, see Solving Merge Conflicts
If you run into trouble with push to the remote repo, this may involve some not so simple troubleshooting. More to come on that later.
git push origin local-name:remote-name
There are two strategies you can use to potentially deal with merge conflicts:
git checkoutgit stash
The git checkout strategy basically involves switching between the local and remote versions of a file. From there you can either choose one version of the file and discard the other; or you can copy the changes out from one or both file versions, edit separately, and then paste it all back into the original file.
The git stash strategy is a bit similar, except you're basically "stashing" files away into an imaginary "box" (stack, more technically). From there you can either act similarly to the first scenario and either use some copy/paste hacking, or simply discard or commit one version of the file before proceeding to merge/edit.
The following section on git diff is intended to give a fuller understanding of what's going on when run a git diff prior to/after running a git fetch, push, or pull.
After you've run your git fetch, before running a git pull it's a good idea to find out which files have changed. After that, you may want to see what specific changes have been made for any given file(s). The following commands will help you do that:
git diff --name-only # See which files you've changed locally
git diff # See the local changes you've made
git diff local_branch remote_branch --name-only # See which files are different local and remote
git diff local_branch remote_branch # Output all the changes to the terminal
git diff local_branch remote_branch filename # Output the changes for the file(s) to the terminal
git diff local_branch remote_branch > diff.sh # Save the ouput to a file instead. This may be easier to read.
# You can also compare two local branches. Ex:
git diff staging master # Show what's been modified on staging relative to masterNote: This section is intended to better explain what you're seeing when you run a git diff. If it feels a bit over-your-head, don't worry about it - simply move to the next section for now.
git diff works by doing the following: git diff base_branch modified_branch. To give a real world example, while working on this doc I added the setup.sh script to the remote repo. To test things out, I made a second copy of the repo, and then ran git diff master origin/master. The output showed up as follows:
$ git diff master origin/master
diff --git a/setup.sh b/setup.sh
new file mode 100644
index 00000000..86b8a34f
--- /dev/null
+++ b/setup.sh
@@ -0,0 +1,17 @@
+# Don\'t mess with the CNAME File!!!!
+git update-index --skip-worktree CNAME
+
+# Add Staging remote and fetch all changes from both remotes
+git remote add staging https://github.com/pgpconference/staging.git
+git pull --all
+
+# Create and checkout local staging branch
+git checkout -b staging
+# Tell staging to track Remote staging:gh-pages
+git branch -u staging/gh-pages
+
+# Pull any changes for the new branch
+git pull --all
+
+# set `push.default` to always have staging push to staging:gh-pages.
+git config push.default upstreamThe above probably looks a bit like gibberish. The important part for us are the sections with the + signs. These are the additions that were made on origin/master - which we don't have on our computer yet.
If I run it with the opposite order git diff origin/master master, it assumes that our local branch is the deviant branch, and instead shows as follows:
$ git diff origin/master master
diff --git a/setup.sh b/setup.sh
deleted file mode 100644
index 86b8a34f..00000000
--- a/setup.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-# Don\'t mess with the CNAME File!!!!
-git update-index --skip-worktree CNAME
-
-# Add Staging remote and fetch all changes from both remotes
-git remote add staging https://github.com/pgpconference/staging.git
-git pull --all
-
-# Create and checkout local staging branch
-git checkout -b staging
-# Tell staging to track Remote staging:gh-pages
-git branch -u staging/gh-pages
-
-# Pull any changes for the new branch
-git pull --all
-
-# set `push.default` to always have staging push to staging:gh-pages.
-git config push.default upstream
Basically it's saying "relative to the master branch, you deleted this file".
One of the reasons that Merge Conflicts are such a pain is that the Git Diff formatting can be really confusing - especially when you're trying to make sense of it in an actual file. Continuing our example from above, let's say I made some local changes without doing a git pull first. When I now run a git pull (after having made the changes), git gives me the following error:
$ git pull
CONFLICT (add/add): Merge conflict in setup.sh
Auto-merging setup.sh
Automatic merge failed; fix conflicts and then commit the result.So then we open up setup.sh to take a look, and we get this mess:
# Don't mess with the CNAME File!!!!
git update-index --skip-worktree CNAME
<<<<<<< HEAD
# Add Staging remote & fetch (pull?) all changes from both remotes
=======
# Add Staging remote and fetch all changes from both remotes
>>>>>>> 7c70bbb390040ca615094b253b7dbe9fe30069e5
git remote add staging https://github.com/pgpconference/staging.git
git pull --all
# Create and checkout local staging branch
git checkout -b staging
# Tell staging to track Remote staging:gh-pages
git branch -u staging/gh-pages
# Pull any changes for the new branch
<<<<<<< HEAD
git pull
=======
git pull --all
>>>>>>> 7c70bbb390040ca615094b253b7dbe9fe30069e5
# set `push.default` to always have staging push to staging:gh-pages.
git config push.default upstreamEven though it's a small file with only a few minor changes, it gets confusing pretty fast - and reassembling it can get really overwhelming! Thankfully we have git checkout to rescue us from this. With git checkout, we can alternate between the two versions of the files by passing the --ours (local) or --theirs (remote) flags. When we do this, git will modify the local file to match whichever version we checked out.
So when we run git checkout --ours setup.sh, we get:
# Don't mess with the CNAME File!!!!
git update-index --skip-worktree CNAME
# Add Staging remote & fetch (pull?) all changes from both remotes
git remote add staging https://github.com/pgpconference/staging.git
git pull --all
# Create and checkout local staging branch
git checkout -b staging
# Tell staging to track Remote staging:gh-pages
git branch -u staging/gh-pages
# Pull any changes for the new branch
git pull
# set `push.default` to always have staging push to staging:gh-pages.
git config push.default upstreamAnd when we run git checkout --theirs setup.sh, we get:
# Don't mess with the CNAME File!!!!
git update-index --skip-worktree CNAME
# Add Staging remote and fetch all changes from both remotes
git remote add staging https://github.com/pgpconference/staging.git
git pull --all
# Create and checkout local staging branch
git checkout -b staging
# Tell staging to track Remote staging:gh-pages
git branch -u staging/gh-pages
# Pull any changes for the new branch
git pull --all
# set `push.default` to always have staging push to staging:gh-pages.
git config push.default upstreamIn this case, since I know that I only made the local modifications as an example, I know that the remote version is actually entirely correct. So I can simply do the following:
git checkout --theirs setup.sh # Switch to the remote version
git add setup.sh # Add setup.sh to staging (i.e. to be commited)
git commit # Finish up the mergeOn the other hand, if there were changes from both files that I wanted, I would do the following:
## 1. Checkout our version
git checkout --ours setup.sh
## 2. Copy/Paste our version into a separate file
## 3. Checkout their version
git checkout --theirs setup.sh # Switch to the remote version
## 4. Either:
# A) Copy/Paste their version into a separate file, and make the changes there. Copy/Paste the changes back into the setup.sh.
# B) Make the changes directly in setup.sh
## 5. Save the changes, and tell Git that we're ready to commit the file
git add setup.sh
## 6. Finish up the merge with git commit.
git commitIf you have multiple files with merge conflicts, you'd have to repeat this process
checkout one version and c/p it to a separate file and then checkout the other version. Having done that, I would then integrate the new changes
Side Note: git checkout is the same command you use to switch branches - clearly it's very versatile! To resolve this
You can also avoid some of the mess from earlier by using git stash, which essentially puts away all the changes into a tiny neat box, to be retrieved later.
Note: the stash works on a last in, first out basis (ex: if I stacked some books, and then took one off the top of the stack) and is zero-indexed, meaning that it counts from zero instead of one. So in order to get the 2nd book down, I would refer to stash@{1}. Example commands:
git stash # Stash all of the files
git stash push filename # Move an individual file onto the stash
git stash list # Displays a list of what's been stashed
git stash show # Displays the stashed file names
git stash show stash@{2} # Displays the stashed files for the third layer down
git stash pop # Pops the most recent change back into reality
git stash pop stash@{1} # Pops the second layer stash back outWhile git stash can save you some of the merge conflict issues, git may still be a bit stubborn if for example, you modified a file without commiting it, and are trying to pop that same file off the stash. This is another situation where I might use a copy/paste hack and just c/p the contents into a new file, delete the saved file, and then pop the stashed version back out, so I can incorporate the new modifications.
git reset --hard remote/branch # automatically reset head to match remote (i.e. discard extra local commits)