-
-
Notifications
You must be signed in to change notification settings - Fork 1
HOWTO dev git
- Clone a repo
- Pull a new, remote branch (non-existing locally)
- Stage everything & commit
- Create & push to remote tracking branches
- Push your commits to the correct origin
- Changing branch during edits or during merge conflicts ("stashing" changes)
- Git Diff among different branches
- Restore files from different branches
- Cherry-picking some commits from a remote "sandbox" repo
- Overwrite master branch with another containing a new reference implementation
- Delete a local or remote branch (DESTRUCTIVE!)
- Reset local changes in case of a wrong, unsuccessful merge or other mistakes
- Remove or cut-off git revision history (DESTRUCTIVE!)
We won't go through all the basics here. so, point your browsers to:
...Take a look at the git manual with a simple:
$> man git <git_command>
...Where <git_command>
is the command for which you're seeking more info.
For instance, clone
, remote
, push
, branch
, merge
or whatever.
This will create a local copy of the remote repo, already linked to the correct remote
origin in <https_github_url>
:
$> git clone <https_github_url>
To create a new local branch based upon an already existing remote branch, first get the updated list of branches from the origin
, using fetch
. Then list the branch names with branch -a
and, finally, switch to the new local branch via checkout
:
$> git fetch origin
$> git branch -v -a
$> git checkout -b <local_branch_name> origin/<remote_branch_name>
To add everything to staging area (before commit):
$> git add .
$> git commit -m <my_awesome_but_meaningful_message>
Either the branch already exists (let's say, case B) or it has to be created by a push
(case A).
1.1 Create a local branch to a non-yet existing remote branch:
$> git checkout -b <feature_or_branch_name>
[...edits + commit...]
1.2. Push using the upstream parameter, to set the default for the remote push
location:
$> git push -u origin f_name
1.3. However when you push some branch for the first time. You need to associate between your local branch and the one at origin
like this:
$> git branch --set-upstream my_branch origin/my_branch
- whenever a remote branch already exists, simply do a:
$> git branch --track f_name origin/f_name
Assuming we have a remote origin origin
, to push the master
branch onto the remote server, simply do a:
$> git push -u origin master
Unresolvable merge conflicts? Someone asked you to edit that file on another branch while you're in the middle of your work on the current branch and you simply cannot commit the current changes due to [insert whatever reason you got]? Just stash away your changes and restore (or delete them) later on!
For ref.: stashing your changes
To stash all the pending changes, just add
them to the staging area and invoke stash
:
$> git add .
$> git stash
When the changes are stashed away, you can change branch (via checkout
), delete the messed-up branch with the stashed changes if it's the case, or do anything else on another branch.
The stash can be restored later on with a simple git stash apply
.
To enlist all the stored stashes, use git stash list
.
To erase just a single stash, use git stash drop <stash_id>
.
To clear all the stash area, use git stash clear
.
Use git diff
to compare differences from the current branch and another (e.g: "feature-whatever"):
$> git diff feature-whatever
To list the changes between 2 different branches (e.g.: "master" & "staging"):
$> git diff master..staging
To list only the file names that have changed between current branch and another one (e.g. "staging"):
$> git diff --name-status staging
To restore a specific file from another branch (e.g. "my-awesome-feature"):
$> git checkout my-awesome-feature -- <file_path_1> <file_path_2> <file_path_3> <...file_path_N>
Wildchars like *
or ?
are supported in file paths.
Retrieve all the latest updates first:
$> git pull
Assuming we have a remote origin origin/sandbox
, if a local sandbox
branch is missing, create it with:
$> git branch --track sandbox origin/sandbox
Display all existing branches (both local and remote):
$> git branch -a
Install the TIG Git front-end for Linux if missing ("TIG" stands for "Text-mode Interface for Git"), which provides also a convenient UI for cherry-picking of individual commits:
On OpenSuse:
$> sudo zypper install tig
On Ubuntu/Debian:
$> sudo apt-get i tig
Launch tig
specifying the remote repo to be displayed:
$> tig origin/sandbox
The UI works similarly to less
, support h
for "help" and q
for "quit". Select and highlight the desired commit and press "C" (capital C
) to create a new cherry-picked commit on the current (local) branch.
Exit with "q" and push the committed changes.
Assuming master
and new_implementation
are local branches already synchronized with their remote counterpart,
that no pending changes are staged, and that a possible backup branch (with a remote counterpart) has already been created for master
, proceed like this:
$> git checkout new_implementation
$> git merge --strategy=ours master # keep the content of this branch, but record a merge
$> git checkout master
$> git merge new_implementation # fast-forward master up to the merge
If you want your history to be a little clearer, I'd recommend adding some information to the merge commit message to make it clear what you've done. Change the second command line to:
$> git merge --strategy=ours --no-commit master
$> git commit # add information to the template merge message
Then push the changes to remote.
To delete a local branch
$> git branch -d the_local_branch
Use -D, instead of -d
to force delete the local branch in case of errors.
To remove a remote branch (if you know what you are doing!): For git v. 1.5+
$> git push origin :remote_branch_name
For git v. 1.7+
$> git push origin --delete remote_branch_name
Do not use this in case of any "rightful" merge that has resulted in merge conflicts.
Use this only when the remote origin has been rebase
d due to history editing.
# Reset local changes:
$> git reset --hard
# Force a rebase while pulling:
$> git pull --rebase
This procedure is useful when creating external teams repo, based upon an existing branch of the main source tree.
Assuming we have this commit history tree:
A <-- B <-- C <-- D <-- E <-- F (HEAD)
Now, suppose we want to "rebase" the commit history to commit "D", setting it as new "root" of the commit tree, while completely pruning the rest. The best thing to do, is to create a temp, orphan branch with the contents of the commit, merging it to master, and then clean out everything.
# Create a new branch with D's content:
# (Checkout to the status of the git repo at commit <D-sha1>; creating a branch named "temp")
$> git checkout --orphan temp <D-sha1>
# Create a new commit that is to be the new root commit
$> git commit -m "new root commit due to rebase and cleanup"
# Rebase the part of history from <D-sha1> & everything else onto the temp branch:
$> git rebase --onto temp <D-sha1> master
# Rebase will checkout automatically to "master" with the above command; we can clean up dead branch:
$> git branch -d temp
# To keep up the repo in good shape:
$> git prune --progress # delete all the objects w/o references
$> git gc --aggressive # aggressively collect garbage; may take a lot of time on large repos
# Force push the changes to the remote origin: (WARNING: this is destructive and will erase remote history)
$> git push -f
Alternatively to the previous prune
and gc
commands, to erase and clean-up the latests log entries, you can issue also the following
# Remove PERMANENTLY from the log history everything up until now:
$> git reflog expire --expire=now --all
$> git gc --prune=now