Frequently asked questions for git and git workflows.
This brings up an interactive interface that moves through each individual change to a file, allowing you to
only stage the changes that you want.
$ git add --patch package.json
diff --git a/package.json b/package.json
index 7a558a3..e03ce3f 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,6 @@
"name": "package",
"version": "0.4.3",
"description": "this is an example package",
- "keywords": ["key", "middleware", "connect"],
"repository": "git://github.com/foo/bar.git",
"author": "Joe Smith <jsmith@google.com> (http://google.com)",
"repository": "git://github.com/foo/bar",
Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? y
$ git commit --amend --only
Or, without staged changes:
--amend
without other options combines the currently staged changes with the last commit and then opens an editor to
update the commit message. If you have staged changes, they will be added.
To update the last message even if there are staged changes (git status
reports files under Changes to be committed
)
then you can use the -o
(or --only
) option to indicate you want to amend the last commit but only use the files
that were previously committed.
git commit --amend <files>
or
If the commit message does not need to be changed, add --no-edit
eg
git commit --amend --all --no-edit
git add file.js # stage the file
git commit # commit the file
Find commits on remote master
branch which are not on our local master
branch:
git cherry -v origin/master master
Find commits on local master
branch which are not on our local feature
branch:
git cherry -v master feature
Find commits added since the 1.0.0
tag:
git cherry -v v1.0.0 master
git reset
git checkout .
git clean -fdx
git branch <branch> # just creates a branch off the current sha
git checkout <branch> # actually moves to the branch
This can be simplified to:
git checkout -b <branch> # branches and moves to the branch in one command
git init
git add .
git commit -m ‘initial commit’
git remote add origin <destination>
git push -u origin master
Delete a local branch feature
:
This will fail if the branch is not merged. To delete the branch regardless:
To delete a remote branch feature
on remote origin
(warning: There is no confirmation!):
Note: git-branch
documentation lists documentation for the option -r
which works on remote tracking branches, not
branches on the remote; git branch -D -r origin/feature
will delete the remote tracking branch origin/feature
,
not the branch feature
on remote origin
. Pulling/fetching from the remote again will recreate that tracking branch.
To delete remote tracking branches that no longer exist on the remote:
After getting the appropriate hash from a command like git log
git diff --name-only cda409f...
If you haven’t ignored anything yet, this creates a .gitignore
file which you probably want to add and track.
git add .gitignore
git commit -m 'added .gitignore'
git push
git push origin branch-name
git checkout . # reset all tracked files
git checkout file.txt # reset file.txt
git checkout somedir/ # reset all files in somedir/
There are multiple ways of squashing commits but the most recommended and straight forward is to use an interactive rebase, eg
git rebase -i HEAD~4 # interactively rebase from 3 commits ago
This command will bring up your editor with some helpful documentation and list of those commits and messages. The commits are listed in order with the oldest commit at the top and the latest commit at the bottom.
pick f53d15b fixed edge case with IE5
pick 930c0e5 added code coverage
pick fa7c471 fixed lint errors
pick fb57c85 added feature Foo
# Rebase 0a4b808..db5d725 onto 0a4b808
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
To squash the last 4 commits into the most recent, you would change pick
to squash
for commits 2, 3, and 4.
pick f53d15b fixed edge case with IE5
squash 930c0e5 added code coverage
squash fa7c471 fixed lint errors
squash fb57c85 added feature Foo
When the file is saved and the editor is quit, git will automatically squash those 4 commits into one. Your editor
will then pop up again allowing you to change the commit message for the resulting commit(s).
Do you want to undo the commit and never see the changes ever again?
git reset --hard HEAD~1
Do you want to keep your changes and just undo the actual act of committing?
git reset HEAD~1
or
git add
simply stages changes to be committed. To undo that action,
all that’s needed is to git reset
the file or list of files.
To undo a commit, see [How do I undo a commit?](http://gitfaq.org/#How do I undo a commit?)
git pull [remote] [branch]
To update using rebase :
git pull --rebase [remote] [branch]
This performs the same as above, but using rebase
instead of merge
.
(See also What is the difference between fetch and pull for more details)
In git, each commit is tagged with a unique SHA-1 hash. These are critical when resolving differences between sources that
have diverged. This sequence of SHAs is referred to as the “history” and “changing history” is regenerating
those hashes via any number of legitimate means.
A modified history makes it very difficult to resolve differences between two repositories because, from git’s perspective,
the SHAs have changed and commits that should refer to the same changes now look to be two different changes at different times.
Rewriting history has a number of legitimate uses but requires communication proportional to the number of people who
have already based development off the history that is to be changed. It is important that changes are resolved before
history is rewritten and that usually means waiting for all important work to be pushed.
Rewriting local history up to the point of shared changes is rarely a problem. The number of people you need to communicate with
is usually limited to just you.
On shared feature branches, the burden of communication increases to the people who are developing with you on that branch. This
is also usually not a problem if you expect branches to be short lived and highly collaborative (assuming high communication).
On mainline branches that anyone could base off of for any arbitrary work (eg “master” or “develop”),
changing history is very problematic and should only be done in extreme cases where the cost is understood.
Problems occur because you can rarely be sure you’ve communicated with everybody you need to in order to
make sure important changes are pushed before a history modification.
See also What is local history/shared history?
git add file.js # the file that needed to be included
git commit --amend # amend the commit done before step 1 with the added file
This will add the file to the previous commit and replace it with a new commit.
This can be simplified into one command:
git commit --amend file.js
If the commit message doesn’t need to be updated:
git commit --amend --no-edit file.js
If all the edited files need to be added to the last commit:
git commit --amend --no-edit --all
Origin is the default name for the remote server. “Remotes” can be named anything, you can see the names of all
your remotes with the command remote
$ git remote -v
origin git@github.com:jsoverson/gitfaq.git (fetch)
origin git@github.com:jsoverson/gitfaq.git (push)
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
This is not an error message and is nothing to be worried about. This is simply a notice
that you are not attached to an actual branch. For example, take the following commits on master
:
Using the example above where the master
branch has commits A-G
, if you check out master you will be placed at the ’tip'
of master, commit G
. If you remain at the tip of a branch, you are considered “attached.”
If you check out an arbitrary commit, you are no longer necessarily associated with a branch and are considered “detached.”
This is useful to explore the state of code at a commit, and you can also create and move to a branch from a “detached head” state.
If this state was unintentional, you can get back to where you likely want to be by checking out the branch you expected to be on, eg
$ git checkout master
Previous HEAD position was 183409d... added file.txt
Switched to branch 'master'
Try navigating through detached head by yourself. The following block sets up a fresh git repository with two commits.
git init
touch file.txt
git add file.txt
git commit -m 'added file.txt'
touch file2.txt
git add file2.txt
git commit -m 'added file2.txt'
HEAD
is now at the tip of master. Check out the previous commit by issuing the command git checkout HEAD~1
which references
the commit 1 before HEAD
.
$ git checkout HEAD~1
git co HEAD~1
Note: checking out 'HEAD~1'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b new_branch_name
HEAD is now at 183409d... added file.txt
To get back to the tip of master, checkout master
.
$ git checkout master
Previous HEAD position was 183409d... added file.txt
Switched to branch 'master'
Notice, though, if you try to check out what commit the tip of master was initially pointing to you still will be
detached!
$ git co ec3...7da
Previous HEAD position was 183409d... added file.txt
HEAD is now at ec36c1b... added file2.txt
$ git status
HEAD detached at ec36c1b
nothing to commit, working directory clean
The term “remote” is any remote destination that you may want to push or pull from. This is often a git
repository hosted on a git server like those run by Github.
You can have multiple remotes.
You can view the remotes you have set with git remote
and git remote -v
gives you more important information.
$ git remote -v
origin git@github.com:jsoverson/gitfaq.git (fetch)
origin git@github.com:jsoverson/gitfaq.git (push)
You can add new remotes via git remote add <destination>
eg
$ git remote add michaelficarra git@github.com:michaelficarra/gitfaq.git
You can change the destination via git remote set-url <remote> <destination>
$ git remote set-url origin git@github.com:michaelficarra/gitfaq.git
master
is the common name for the default branch. It doesn’t need to exist, but it often does.
HEAD
can be thought of as a variable pointing to a specific commit. It can change and isn’t related to a branch.
Issuing new commits changes HEAD
, checking anything out changes HEAD
.
“Remote history” or “Shared History” is used to refer to history that is shared with others. “Local history” is used to
refer to changes that have never been shared.
For the following commit history, “Shared History"and “Local History” boundaries are shown,
A-B-C-D-E origin/master
A-B-C-D-E-F-G-H-I origin/feature1
A-B-C-D-E-F-G-H-I-J-K-J feature1 (local)
| | | | | |
| | | | +-+-+
| | | | |
| | +--+--+ Local History
| | |
+---+---+ Shared History (branch)
|
Shared History (master)
Rebasing is establishing a new base for a series of commits.
In the example below, the branch feature
deviated at commit B
, while the master
branch moved along in parallel.
A-B-C-D-E master
\
X-Y-Z feature
You can rebase with the rebase
command. For example, to rebase the feature
branch on master
:
$ git checkout feature
$ git rebase master
Rebasing essentially rewinds the commits on a branch, brings the branch up to date with the rebase target, and then
replays the rewound commits over it, leaving the timeline looking like this.
A-B-C-D-E master
\
X'-Y'-Z' feature
Warning this changes history, see also What does changing history mean?
Squashing is the act of turning multiple git commits into fewer. There are many reasons you might want to do this but the most straightforward is to simply keep the commit history cleaner and filled with high value changes.
Consider the following set of commits
f53d15b fixed edge case with IE5
930c0e5 increased code coverage
fa7c471 fixed lint errors
fb57c85 added feature Foo
In a local repository that level of detail may be useful; at some point a regression may have been introduced
while fixing lint errors and you would be able to revert to a previous commit to do some testing.
In the grand scheme of living software, this level of granularity becomes noisier than it is worth. When preparing code
to enter a main line branch it can become more valuable to squash commits into logical chunks so that the history becomes
more valuable as a record of important changes. The following commits could then be squashed into a single commit, eg
a3545a5 added feature Foo
See also how do I squash commits?
git pull [remote] [branch]
is the same as
git fetch [remote] [branch]
git merge [remote][/branch]
git pull --rebase [remote] [branch]
is the same as
git fetch [remote] [branch]
git rebase [remote][/branch]