Skip to content

Git flow for pros

Michael Hulse edited this page Jun 25, 2021 · 35 revisions

Cherry pick

Git check out tag, then check out temp branch (git branch tmp), git cherry-pick hash onto this temp local branch, resolve conflicts/make any changes and commit them locally, then tag tmp branch and push tag. This tag can then be used by ENG to work from until they can update to latest master. You can push branch up if you like, to keep it somewhere safe, or just keep it around locally until ENG has moved on and release is good to go.

Checkout specific file from another branch

Useful if you modify a file that you want to reset:

$ git co master -- public_html/assets/plugins/bootstrap-3.3.7/css/bootstrap.min.css

Searching through git revisions

$ git grep "\$userCoaches" $(git rev-list --all)

The quote = regex, so escaping the dolla dolla sign is needed.

Update a local branch that has been force pushed

$ git co feature-branch
$ git fetch
$ git reset origin/feature-branch --hard
# or --soft to keep local tracked changes.

See: git pull after forced update

Delete branches locally other than master

$ git branch | grep -v "master" | xargs git branch -D

Syncing a fork

$ git remote -v
$ git remote add upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git
$ git remote -v
$ git fetch upstream
$ git checkout master
$ git merge upstream/master

Mirroring master to gh-pages:

$ git checkout -B gh-pages master # Check out to gh-pages, starting from master
$ git checkout master # Move back to master

Pushed a bad commit to master and want to revert to previous commit

# Find last shared commit (e.g., if on master, go back to where branches converge):
$ git reset --hard f209b0e
$ git push -f
# If on Bitbucket, you will see “Commit deleted …” in the “Recent Activity” feed.

Merge conflicts with master when on a feature branch

If you see something like:

$ git rebase -i master
error: could not apply 2146ce7... Working on it

First, fix the merge conflicts in your file(s) and then do this:

# You must edit all merge conflicts and then mark them as resolved using:
$ git add .
# Continue the rebase:
$ git rebase --continue

That’s it!

Vim essential edit commands:

  1. a: Append text after the cursor [count] times.
  2. A: Append text at the end of the line [count] times.
  3. i: Insert text before the cursor [count] times.
  4. I: Insert text before the first non-blank in the line [count] times.
  5. gI: Insert text in column 1 [count] times.
  6. o: Begin a new line below the cursor and insert text, repeat [count] times.
  7. O: Begin a new line above the cursor and insert text, repeat [count] times.

Tagging releases

$ git co master
$ git tag -a 'v0.3.0' -m 'Client-approved functionality.'
# List local tags:
$ git tag
v0.1.0
v0.2.0
v0.3.0
$ git push origin --tags

Checkout a specific tag:

$ git checkout tags/<tag_name>

Accidentally changed files on branch that's already been merged and deleted on remote repo

# On local feature branch that's been deleted on remote repo:
$ git push -u origin feature-branch
# Above creates new branch.
$ git commit -am 'Message'
$ git push
$ git co master && git fetch && git pull
$ git co feature-branch
$ git rebase master
# Force it:
$ git push -f origin feature-branch

Alternatively, you could create a new branch off of the remotely-deleted feature-branchand push, then rebase on master and do a force push.

Local branch goes to shit …

When git reset --hard doesn’t seem to work … Delete it and then pull it fresh:

$ git branch -D feature-branch
$ git fetch origin feature-branch
$ git checkout -b feature-branch origin/feature-branch

Create a gh-pages-only repo

Useful for repos hosted on GitHub that want to take advantage of GitHub pages:

# Create and clone your repo, then …
# Create the gh-pages branch:
$ git checkout -b gh-pages
# … and push:
$ git push -u origin gh-pages

Now, via the GitHub interface, click on your repo’s settings link and choose gh-pages as your default branch:

default

Back in the command line (this step is optional; only do this if you don’t want master floating around):

# Delete local master branch:
$ git branch -D master
# Delete remote master branch:
$ git push origin --delete master

Pushing a new feature branch

In recent Git 1.7.0+ you can do the following:

$ git checkout -b feature_branch_name
# ... edit files, add and commit ...
$ git push -u origin feature_branch_name
# -u is short for --set-upstream

It's also worth noting that if you have an existing tracking branch already set on the branch you're pushing, and push.default is set to upstream, this will not do what you think it will do. It will try to push over the existing tracking branch. Use: git push -u origin mynewfeature:mynewfeature or do git branch --unset-upstream first.

http://stackoverflow.com/a/6232535/922323

Reset feature branch to what’s on master

Just do:

$ git reset --hard master

Adding features to a feature branch and rebasing

On feature branch (it is assumed that changes have already been made):

$ git add .
$ git commit -a
# Or, if not needing more than one line:
#$ git commit -am

In editor, type i for insert mode.

First line should be title of commit … If using issue tracking system, like JIRA, put the issue number in parenthesis at the end.

Additional lines should be what was completed (with \n\n separators).

To finish, type :wq for “write and quit”.

Next, get latest commits from origin:

$ git checkout master

Check if there's anything new:

#$ git remote update && git status
# Faster to use:
$ git fetch

If so, run:

$ git fetch origin
$ git pull origin master
# This would work too:
#$ git fetch
#$ git pull

Go back to your feature branch:

$ git co feature-branch

And rebase:

$ git rebase -i master

When in VIM editor mode, use:

# Remove an entire line:
dd
# Remove first word and replace with another:
cw and hit s (squash) or f (fixup) or p (pick) to keep intact or r (reword)
# Exit insert mode:
esc
# Save:
:wq write quit
# Force quit, but this may save:
:q! force quit
# This will force an error to VIM and it will not save any changes:
:cq!

Use git log (or git log oneline) to see the clean/new commit message (previous commits to this feature branch should be gone/squashed into the latest commit at top).

Once that's complete, use:

$ git push -f origin feature-branch 

Where the -f means force; we’re doing this due to the history change.

Never do a --force on master!

Next visit BitBucket (or GitHub) and use web interface; visit the branches section and switch to your feature-branch.

You should see your updated/squashed code; at this point, let the reviewer know you’ve updated things and they can take another look.

If your commit is approved, and once the code is merged, check out and update your master branch:

$ git checkout master
$ git fetch origin
$ git pull origin master
$ git status

DONE! 👍

If there’s merge conflicts, do this …

If you committed your work, made some more changes, and there are conflicts:

$ git reset --hard origin/feature-branch
$ git rebase -i master
$ git status
$ git add .
$ git status
# Continue the rebasing process:
$ git rebase --continue
# You should now see only one commit message at top:
$ git log
$ git push --force

If master branch gets updated whilst working on a feature branch, do this …

If different files were touched, outside of the files you are touching in your feature branch, then you should not need to worry. BUT, better safe than sorry:

$ git co master 
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git fetch
remote: Counting objects: 1, done.
remote: Total 1 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (1/1), done.
From bitbucket.org:ieq/parent-net-api
   bf445e7..100a1ca  master     -> origin/master
$ git pull
Updating bf445e7..100a1ca
Fast-forward
 client/js/controllers/childDetail.js   | 49 +++++++++++++++++++++++++------------------------
 client/js/controllers/modalInstance.js | 10 +++++++++-
 client/views/modal.html                |  1 +
 3 files changed, 35 insertions(+), 25 deletions(-)
$ git co 66-header-
# Hit tab twice to see available feature branches:
66-header-css-layout-fix   66-header-fix              
$ git co 66-header-css-layout-fix 
Switched to branch '66-header-css-layout-fix'
$ git rebase master
First, rewinding head to replay your work on top of it...
Fast-forwarded 66-header-css-layout-fix to master.

If there were merge conflicts, rebase would have made you fix them and then you would do a force push to your feature branch:

$ git push --force

If upstream feature branch updated, do this …

$ git status
On branch FEATURE-BRANCH
Your branch is up-to-date with 'origin/FEATURE-BRANCH'.
nothing to commit, working directory clean
$ git fetch
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 5 (delta 3), reused 0 (delta 0)
Unpacking objects: 100% (5/5), done.
From bitbucket.org:ieq/repo
 + 59e4f8e...8cef25d FEATURE-BRANCH -> origin/FEATURE-BRANCH  (forced update)
 + 0a9981a...c90c725 FEATURE-BRANCH -> origin/FEATURE-BRANCH  (forced update)
$ git reset --hard origin/FEATURE-BRANCH 
HEAD is now at 8cef25d COMMIT MESSAGE

The trick here, is the forced update line; this is a signal that you can use reset --hard.

Notes and tips

In a team or open source environment, it’s preferable to have a workflow that involves feature branches, squash commits, and make pull requests.

If using a tracking system, name your branches with the issue number at front, like so:

99-my-feature-branch

This make it easy to checkout because you probably already know the issue number.

When creating commit messages, append the full issue number to the end of the message’s first line:

$ git commit -am 'This is my feature branch that fixes issue XXXXXX (PAR-99).

Depending on the issue tracking software, the issue number should then create a cross-link between the issue and the commit message (e.g. BitBucket and Jira).


If you ever get stuck on a feature branch during an update, run:

$ git reset --hard origin/feature-branch

If master ever gets fucked, you can also do this:

$ git co master
$ git reset --hard origin/master

If all else fails, delete your local repo and re-clone! 😄


# Diff between current branch and master:
$ git diff master
# Diff between branch A and branch B (even if on branch C):
$ git diff branch-A branch-B

Cheat sheet for print:

rebase

# Adding features to a feature branch and rebasing
$ git add -a
$ git commit -m 'Commit message (issue number)' # Adds all tracked files to staging area and commits.
# OR:
# $ git commit -a # Commits all local changes in tracked files + editor.
# Vim: Type i for insert mode.
# First line should be title of commit …
# If using issue tracking system, like JIRA,
# put the issue number in parenthesis at the end.
# Additional lines should be a log of the work
# completed (with \n\n separators).
esc
:wq
$ git push # Optional.
# OR, if pushing for first time:
# $ git push --set-upstream origin feature-branch
$ git checkout master
$ git fetch && git pull
$ git checkout feature-branch
# Only do if multiple commits in history:
$ git rebase -i master
# Vim step 1:
cw and hit s (squash) or f (fixup) or p (pick) to keep intact or r (reword)
Note: keep first line as pick, and squash the rest.
esc
:wq (write and quit)
# Vim step 2:
dd  (remove entire line)
a   (append text after the cursor)
A   (append text at the end of the line)
i   (insert text before the cursor)
I   (insert text before the first non-blank in the line)
gI  (insert text in column 1)
o   (begin a new line below the cursor and insert text)
O   (begin a new line above the cursor and insert text)
esc
:wq (write and quit)
$ git log --oneline
$ git push -f origin feature-branch
# Never do a --force on master!
$ git checkout master
$ git fetch && git pull
$ git status
Clone this wiki locally