-
Notifications
You must be signed in to change notification settings - Fork 18
Git : Advanced Topics
- Avoid asking username (HTTPS connection)
- Setting up an ssh connection
- Differences between commits
- Differences in your working copy
- Overwrite branches
As a default, git will always ask for your username and password if you have your connection set up for an HTTPS connection. Storing your credential is usually not a safe practice, but storing your username should not be so terrible and reduces in half the hassle in your pushes.
Check the .git/config
file and add your username in the "url" section of the desired remote. For example, it should read something like url = https://[email protected]
.
You can clone repositories using https or ssh (you will need to set up the public key first). Replace the user_name, the local_name and the source path (MALBECC) as appropriate.
# using https
git clone https://[USER_NAME]@github.com/MALBECC/lio [LOCAL_NAME]
# using ssh
git clone [email protected]:MALBECC/lio.git [LOCAL_NAME]
$ git rev-parse (--short) [LONG_SHA/or/BRANCH_NAME]
When comparing two commits, it is usually a good idea to start by just checking/listing which files have been modified, and then see the differences in each one of them. To do this, run the following commands respectively:
$ git diff --name-status [SHA_i] [SHA_f]
$ git diff [SHA_i] [SHA_f] -- [path/to/file.ext]
You may run --name-only
instead of --name-status
, but this last one will give you the extra piece of information of whether the file has been added, modified, or deleted. You may also use other pointers to the commits others than the SHAs, such as the branch names (if you want to compare the last commits of two branches). Lastly, if you want to compare two different files (maybe because you changed the name but the content should be the same), you can run:
$ git diff [SHA_i]:[path/to/file_i.ext] [SHA_f]:[path/to/file_f.ext]
Your working copy is the your current status, which may have files that are modified but not yet commited. If you want to see the differences between that and the files in another branch, you can use the following commands:
$ git diff --name-status [SHA_0]
$ (list of files)
$ git diff [SHA_0] -- [path/to/file_0.ext]
$ git merge-base [SHA_0] [SHA_1]
$ (SHA_OF_ANCESTOR)
$ git log (--pretty=oneline) [SHA_OF_ANCESTOR]..[SHA_1]
git branch -d the_local_branch
git push origin :the_remote_branch
git branch -m <oldname> <newname>
git branch [local_branch_name] [remote_name]/[branch_name]
Stashing is a useful tool for when you want to save some changes you are currently working on without actually committing them to the history. This is useful in a variety of situations: if you need to change branches for a second to check something out, or rebase your current branch without actually commiting your current changes, etc.
Simply running git stash
will create a new local stash into your stack and clean your current directory. To see all the available stashes, you can run git stash list
. To reload a stash in your stack into the current commit, you can use git stash apply stash@{n}
(where n is the stash number id shown when listing). The commit where you apply the stash needs not be the same in which the stash was created (though if it's not, conflicts might need to be resolved). Note that the stash will not be automatically removed when re-applied, it will be kept at the list unless you manually remove it by using git stash drop stash@{n}
; keep your stack clean and don't let stashes accumulate!
What if you have committed something and immediately realize there was some minor detail missing? You can then run git commit --amend
to overwrite your last commit.
Please note that when you do this you are in fact overwriting history; this will probably be fine at a local level and with such "recent" history, but never ever rewrite a commit that has already been pushed to github. This may create all sort of compatibility problems if the other users have already included said commit to their own history and their own work.
If you do, by mistake, amend commit you have just pushed, a simple solution to this is to simply pull from the remote repository, which will overwrite your amend and you will be again in sync. Usually you don't have to worry about rewriting the history in github because git won't allow you to push if that is the case. That is, unless you explicitly force the pull: as a general rule, never force anything.
To overwrite a local branch with the content of a remote branch, checkout that branch and run git reset --hard <remote>/<branch>
. To overwrite the branch in a remote repository with the current commit, run git push -f <remote> <branch>
. Be careful with this last one, the history of other people sharing this repository will conflict with the new one, and if they have any local commits after the point of change they will become invalid.
A slightly safer option might be git push <remote> <branch> --force-with-lease
: this will fail if your local reference to that remote branch differs from the actual remote branch (that is to say, if there has been any recent commits since your last fetch). This still won't prevent major messups.
git fetch --prune --all
For (almost) every commit you do, git will save a snapshot of the code at that given time. As time progresses and the code with it, so will the number of saved commits grow, ever increasing. It is therefore advisable to give a minimal amount of consideration to when a change deserves to be committed and when it is better to accumulate more changes before that.
This is not to say that commits are not allowed until the feature is completed and debugged, but it if you are simply debugging a portion of the code, committing after each word corrected is probably not a good idea either. A good criteria is that every commit should be a useful reference point, distinct from the previous one at least in some sense. Going back to the debug example, it probably could be a good idea to commit after each major advancement in the debug (if you manage to get NaN's from a code that was dumping cores, or later if you get wrong numbers from a code that was returning NaN's, etc.) or after major modifications of the code itself.
Adhering to this guideline can be difficult, specially when you need to switch branches and git won't let you if you haven't commited, or if you need to save your changes now for any reason but you don't really want them to be a commit yet. Here are some tools that may help you in that respect; but if it ever comes to it, it is not terrible to do one "bad" commit once in a while, as long as you keep the good habits.
http://stackoverflow.com/questions/1186535/how-to-modify-a-specified-commit-in-git http://stackoverflow.com/questions/3926768/amend-a-commit-that-wasnt-the-previous-commit/3926832#3926832
(go to command summary)
A repository is a complete copy of the code, its current branches and all its history. The main online repository of LIO is the github repository hosted here (MALBECC/lio), and developers will generally have their own github forks (USER/lio). These forks will basically act as mediators when sending changes to the official code (as well as online backups and sharing tool), but they will also have many local copies of their online repository in their workstations, so it is important to know how to keep all copies organized and in sync.
You can check the remote repositories that your local one sees, and add new ones or change existing ones (change their name, change their address or delete them). Again, you can set things using https or ssh.
git remote -v
git remote add upstream https://[USER_NAME]@github.com/MALBECC/lio.git
git remote rename [OLD_NAME] [NEW_NAME]
git remote set-url upstream [email protected]:MALBECC/lio.git
git remote rm [REMOTE_NAME]
You can list your local branches and your remote branches (or both at once). You can also see which remote branches are linked to your local branches and change their setup. How you do this last part may vary according to which version of git you have.
git branch
git branch -r
git branch -a
git branch -vv
git branch --set-upstream [LOCAL_BRANCH] [REMOTE_REPO]/[REMOTE_BRANCH]
git branch [LOCAL_BRANCH] --set-upstream-to=[REMOTE_REPO]/[REMOTE_BRANCH]
git branch --unset-upstream [LOCAL_BRANCH]
To safely update the references to your remotes, it is recommended not to pull directly (which may overwrite your local branches) but to use fetch instead. Then check those changes and only then update the branch. Always try first to fast forward; if you can't, double check changes before forcing a reset. You shouldn't be merging into new commits when updating changes like this.
git fetch -p
git diff [LOCAL_BRANCH] [REMOTE_REPO]/[REMOTE_BRANCH]
git checkout [LOCAL_BRANCH]
git merge -ff-only [REMOTE_REPO]/[REMOTE_BRANCH]
git reset --hard [REMOTE_REPO]/[REMOTE_BRANCH]
git remote show <remote-name>
https://stackoverflow.com/questions/3471827/how-do-i-list-all-remote-branches-in-git-1-7
git fetch -p [remote_name]
git diff [branch_name] [remote_name]/[branch_name]
git checkout [branch_name]
git merge [remote_name]/[branch_name]
https://stackoverflow.com/questions/5751582/fetch-from-origin-with-deleted-remote-branches
https://robots.thoughtbot.com/git-interactive-rebase-squash-amend-rewriting-history
http://www.benjaminlhaas.com/blog/locally-and-remotely-renaming-branch-git
http://stackoverflow.com/questions/4753888/git-renaming-branches-remotely
http://stackoverflow.com/questions/6591213/how-do-you-rename-the-local-branch
https://git-scm.com/book/it/v2/Git-Branching-Remote-Branches
TOADD: LIO remote repositories on github are sacred; you should never rewrite its history or play with its configuration. What you do in your local repository, however, is up to you and you alone; but always remember, for as it is yours the freedom to do as you please with your repository, it is yours as well the responsibility to then make it comply with our standards when presenting your work back in our shared repository. At the end of the day, however you get there, what you have locally will have to agree with what there is in github or you won't be allowed to push (and you should never force a push that was not allowed).