Friday, February 26, 2016

Git Misc Part 3



http://massivetechinterview.blogspot.com/2016/07/git-misc-part-4.html

Make easier for review
Don't pollute history

Make pr cleaner:
Undo commit

https://www.atlassian.com/git/tutorials/undoing-changes#git-checkout
The git checkout command serves three distinct functions: checking out files, checking out commits, and checking out branches

The git revert command undoes a committed snapshot. But, instead of removing the commit from the project history, it figures out how to undo the changes introduced by the commit and appends a new commit with the resulting content.

Reverting has two important advantages over resetting. First, it doesn’t change the project history, which makes it a “safe” operation for commits that have already been published to a shared repository. For details about why altering shared history is dangerous, please see the git reset page.
Second, git revert is able to target an individual commit at an arbitrary point in the history, whereas git reset can only work backwards from the current commit. For example, if you wanted to undo an old commit with git reset, you would have to remove all of the commits that occurred after the target commit, remove it, then re-commit all of the subsequent commits. Needless to say, this is not an elegant undo solution.

Don’t Reset Public History

You should never use git reset <commit> when any snapshots after <commit> have been pushed to a public repository. After publishing a commit, you have to assume that other developers are reliant upon it.
The point is, make sure that you’re using git reset <commit> on a local experiment that went wrong—not on published changes. If you need to fix a public commit, the git revert command was designed specifically for this purpose.
The git clean command is often executed in conjunction with git reset --hard. Remember that resetting only affects tracked files, so a separate command is required for cleaning up untracked ones. Combined, these two commands let you return the working directory to the exact state of a particular commit.
git clean -n
Perform a “dry run” of git clean. This will show you which files are going to be removed without actually doing it

Don’t amend public commits

Amended commits are actually entirely new commits and the previous commit will no longer be on your current branch. This has the same consequences as resetting a public snapshot. Avoid amending a commit that other developers have based their work on.
https://git-scm.com/book/en/v2/Git-Basics-Undoing-Things

Unmodifying a Modified File

  (use "git checkout -- <file>..." to discard changes in working directory)

$ git checkout -- CONTRIBUTING.md

Changing the Last Commit



$ git commit --amend


https://git-scm.com/docs/git-reset
$ git reset --hard HEAD~3   (1)
  1. The last three commits (HEAD, HEAD^, and HEAD~2) were bad and you do not want to ever see them again. Do not do this if you have already given these commits to somebody else
https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified


HEAD is the pointer to the current branch reference, which is in turn a pointer to the last commit made on that branch. That means HEAD will be the parent of the next commit that is created. It’s generally simplest to think of HEAD as the snapshot of your last commit on that branch.


Then we run git commit, which takes the contents of the Index and saves it as a permanent snapshot, creates a commit object which points to that snapshot, and updates master to point to that commit.


Switching branches or cloning goes through a similar process. When you checkout a branch, it changes HEAD to point to the new branch ref, populates your Index with the snapshot of that commit, then copies the contents of the Index into your Working Directory.

Step 1: Move HEAD



The first thing reset will do is move what HEAD points to. This isn’t the same as changing HEAD itself (which is what checkout does); reset moves the branch that HEAD is pointing to. This means if HEAD is set to the master branch (i.e. you’re currently on the master branch), running git reset 9e5e6a4will start by making master point to 9e5e6a4.



No matter what form of reset with a commit you invoke, this is the first thing it will always try to do. With reset --soft, it will simply stop there.

When you run git commit, Git creates a new commit and moves the branch that HEAD points to up to it. When you reset back to HEAD~ (the parent of HEAD), you are moving the branch back to where it was, without changing the Index or Working Directory. You could now update the Index and run git commit again to accomplish what git commit --amend would have done 



Step 2: Updating the Index (--mixed)



The next thing reset will do is to update the Index with the contents of whatever snapshot HEAD now points to.
If you specify the --mixed option, reset will stop at this point. This is also the default, so if you specify no option at all (just git reset HEAD~ in this case), this is where the command will stop.
Now take another second to look at that diagram and realize what happened: it still undid your last commit, but also unstaged everything. You rolled back to before you ran all your git add and git commit commands.

Step 3: Updating the Working Directory (--hard)

The third thing that reset will do is to make the Working Directory look like the Index. 


The reset command overwrites these three trees in a specific order, stopping when you tell it to:
  1. Move the branch HEAD points to (stop here if --soft)
  2. Make the Index look like HEAD (stop here unless --hard)
  3. Make the Working Directory look like the Index

Squashing



You can run git reset --soft HEAD~2 to move the HEAD branch back to an older commit (the most recent commit you want to keep):


And then simply run git commit again:
Running git checkout [branch] is pretty similar to running git reset --hard [branch] in that it updates all three trees for you to look like [branch], but there are two important differences.
First, unlike reset --hardcheckout is working-directory safe; it will check to make sure it’s not blowing away files that have changes to them. Actually, it’s a bit smarter than that — it tries to do a trivial merge in the Working Directory, so all of the files you haven’t changed in will be updated. reset --hard, on the other hand, will simply replace everything across the board without checking.
The second important difference is how checkout updates HEAD. Whereas reset will move the branch that HEAD points to, checkout will move HEAD itself to point to another branch.


For instance, say we have master and develop branches which point at different commits, and we’re currently on develop (so HEAD points to it). If we run git reset masterdevelop itself will now point to the same commit that master does. If we instead run git checkout masterdevelop does not move, HEAD itself does. HEAD will now point to master.



The other way to run checkout is with a file path, which, like reset, does not move HEAD. It is just like git reset [branch] file in that it updates the index with that file at that commit, but it also overwrites the file in the working directory. It would be exactly like git reset --hard [branch] file (if reset would let you run that) — it’s not working-directory safe, and it does not move HEAD.
https://git-scm.com/blog
https://makandracards.com/makandra/621-git-delete-a-branch-local-or-remote
To delete a local branch
COPY
git branch -d the_local_branch
To remove a remote branch (if you know what you are doing!)
COPY
git push origin :the_remote_branch
or simply use the new syntax (v1.7.0)
COPY
git push origin --delete the_remote_branch

Note

If you get the error error: unable to push to unqualified destination: the_remote_branch The destination refspec neither matches an existing ref on the remote nor begins with refs/, and we are unable to guess a prefix based on the source ref. error: failed to push some refs to 'git@repository_name'
perhaps someone else has already deleted the branch. Try to synchronize your branch list with
COPY
git fetch -p
The git manual says -p, --prune After fetching, remove any remote-tracking branches which no longer exist on the remote.
https://git-scm.com/book/en/v2/Git-Branching-Rebasing
In Git, there are two main ways to integrate changes from one branch into another: the merge and the rebase.

The easiest way to integrate the branches, as we’ve already covered, is the merge command. It performs a three-way merge between the two latest branch snapshots (C3 and C4) and the most recent common ancestor of the two (C2), creating a new snapshot (and commit).

If you examine the log of a rebased branch, it looks like a linear history: it appears that all the work happened in series, even when it originally happened in parallel.

If you examine the log of a rebased branch, it looks like a linear history: it appears that all the work happened in series, even when it originally happened in parallel.
Often, you’ll do this to make sure your commits apply cleanly on a remote branch — perhaps in a project to which you’re trying to contribute but that you don’t maintain. In this case, you’d do your work in a branch and then rebase your work onto origin/master when you were ready to submit your patches to the main project. That way, the maintainer doesn’t have to do any integration work — just a fast-forward or a clean apply.
https://git-scm.com/book/en/v2/Git-Basics-Tagging
Git supports two types of tags: lightweight and annotated.
A lightweight tag is very much like a branch that doesn’t change — it’s just a pointer to a specific commit.
Annotated tags, however, are stored as full objects in the Git database. They’re checksummed; contain the tagger name, email, and date; have a tagging message; and can be signed and verified with GNU Privacy Guard (GPG). It’s generally recommended that you create annotated tags so you can have all this information; but if you want a temporary tag or for some reason don’t want to keep the other information, lightweight tags are available too.
$ git tag -a v1.4 -m "my version 1.4"
$ git tag

$ git show v1.4
https://www.drupal.org/node/1066342
 git tag 7.x-1.0
Once the tag is created, you need to push the tag up to the master repository. By itself, push doesn't send the tags up, you also need to tell it to include the tags in the push by appending the --tags flag:
git push --tags
If you don't want to push all your tags, you can also be specific:
Example:
git push origin tag 7.x-1.0
To check and confirm remote tags, the command is
git tag -l
Let’s tag the version prior to the current version with the name v1-beta. First of all we will checkout the previous version. Instead of looking up the hash, we are going to use the ^ notation indicating “the parent of v1”.
If the v1^ notation causes troubles, try using v1~1, referencing the same version. This notation means “the first version prior to v1”.

RUN:


git checkout v1^
git tag v1-beta
git checkout v1-beta

https://stackoverflow.com/questions/10312521/how-to-fetch-all-git-branches
You can fetch one branch from all remotes like this:
git fetch --all
fetch updates local copies of remote branches so this is always safe for your local branches BUT:
  1. fetch will not update local branches (which track remote branches); If you want to update your local branches you still need to pull every branch.
  2. fetch will not create local branches (which track remote branches), you have to do this manually. If you want to list all remote branches: git branch -a
To update local branches which track remote branches:
git pull --all
However, this can be still insufficient. It will work only for your local branches which track remote branches. To track all remote branches execute this oneliner BEFORE git pull --all:
git branch -r | grep -v '\->' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done

TL;DR version

git branch -r | grep -v '\->' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done
git fetch --all
git pull --all

Run the first command only if there are remote branches on the server that aren't tracked by your local branches.
http://support.beanstalkapp.com/article/986-how-do-i-deal-with-conflicts-in-my-git-repo
Dealing with "deleted by us" and "deleted by them" conflicts
For some conflict notifications, Git will include a "Deleted by us" or "Deleted by them" message next to a file. That means that you modified a file in one branch and deleted it in another. Git has no way of knowing if you want to delete the file or modify it, so you need to make the choice yourself.
Dealing with this type of conflict is straightforward: you have to decide if the deleted file is still required. You can do that by opening the file and looking at its contents. If you want to keep the file deleted, use the "rm” command (for the command line). Otherwise, use the "add” command to restore the file. This will resolve the conflict for that file.









  • Keep every feature or bug fix in a separate branch.
  • Keep your local repository up to date. Make regular pulls from the remote to ensure that your local repository has all the recent commits from your team.
  • If you’re working in a branch, merge stable into it at least once a day.
  • Instead of infrequent commits with a large number of changes, do regular small commits often. 
  • Each commit should address a single particular part of the bigger project you’re working on.
  • Push commits to the remote right after you made them. In other words, don’t hoard commits in your local repo.

http://stackoverflow.com/questions/4099742/how-can-i-compare-files-from-two-different-branches
git diff ..master path/to/file
The double-dot prefix means "from the current working directory to". You can also say:
  • master.., i.e. the reverse of above. This is the same as master.
  • mybranch..master, explicitly referencing a state other than the current working tree.
  • v2.0.1..master, i.e. referencing a tag.
  • [refspec]..[refspec], basically anything identifiable as a code state to git.
https://cnodejs.org/topic/5753a3f72420978970d4a626

List Git commits not pushed to the origin yet
http://stackoverflow.com/questions/3080509/list-git-commits-not-pushed-to-the-origin-yet
git log origin/master..master
or, more generally:
git log <since>..<until>
Viewing Unpushed Git Commits
git log origin/master..HEAD
You can also view the diff using the same syntax
git diff origin/master..HEAD
Git Rebase
http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html
A word of caution: Only do this on commits that haven’t been pushed an external repository. If others have based work off of the commits that you’re going to delete, plenty of conflicts can occur. Just don’t rewrite your history if it’s been shared with others.
$ git rebase -i HEAD~4
So, a few things have happened here. First of all, I told Git that I wanted to rebase using the last four commits from where the HEAD is with HEAD~4. Git has now put me into an editor with the above text in it, and a little explanation of what can be done. You have plenty of options available to you from this screen, but right now we’re just going to squash everything into one commit. So, changing the first four lines of the file to this will do the trick:
pick 01d1124 Adding license
squash 6340aaa Moving license into its own file
squash ebfd367 Jekyll has become self-aware.
squash 30e0ccb Changed the tagline in the binary, too.

http://stackoverflow.com/questions/16595908/git-exit-vim-without-commiting
When I use git commit --amend or git rebase -i, vim opens up for me to make changes. If I then change my mind and exit vim without making any changes, a commit is still made which shows up in git reflog.
To get git to not make a change when you are executing git commit --amend or git rebase -i.
Just delete the message (and save). All git does is look for a non empty message to see if a valid commit happened. Since there is a commit message (because you commited something before) git thinks that its a valid commit or rebase.
:cq!
This will force an error to VIM and it will not save any changes.
http://stackoverflow.com/questions/27226886/how-to-abort-a-git-rebase-in-interactive-editor
You can use
:%d|x
to delete all lines, then save and quit
http://stackoverflow.com/questions/927358/how-do-you-undo-the-last-commit

Undo a commit and redo

$ git commit -m "Something terribly misguided"              (1)
$ git reset --soft HEAD~                                    (2)
<< edit files as necessary >>                               (3)
$ git add ...                                               (4)
$ git commit -c ORIG_HEAD                                   (5)
  1. This is what you want to undo
  2. This is most often done when you remembered what you just committed is incomplete, or you misspelled your commit message1, or both. Leaves working tree as it was before git commit.
  3. Make corrections to working tree files.
  4. git add whatever changes you want to include in your new commit.
  5. Commit the changes, reusing the old commit message. reset copied the old head to .git/ORIG_HEADcommit with -c ORIG_HEAD will open an editor, which initially contains the log message from the old commit and allows you to edit it. If you do not need to edit the message, you could use the -C option instead.
rename branch:
https://multiplestates.wordpress.com/2015/02/05/rename-a-local-and-remote-branch-in-git/
1. Rename your local branch.
If you are on the branch you want to rename:
1
git branch -m new-name
If you are on a different branch:
1
git branch -m old-name new-name
2. Delete the old-name remote branch and push the new-name local branch.
1
git push origin :old-name new-name
3. Reset the upstream branch for the new-name local branch.
Switch to the branch and then:
1
git push origin -u new-name
http://www.benjaminlhaas.com/blog/locally-and-remotely-renaming-branch-git
http://www.hostingadvice.com/how-to/git-branch-rename/
If you’re just looking for the command to rename a remote Git branch, this is it:
git push -u origin feature2:feature3

git help branch
http://serverfault.com/questions/175052/how-to-tell-which-local-branch-is-tracking-which-remote-branch-in-git
For all branches:
git branch -avv
For local branches only:
git branch -lvv
shows you all branches as well as the name of the upstream branch
-a shows all local and remote branches, while -rshows only remote branches.
http://stackoverflow.com/questions/171550/find-out-which-remote-branch-a-local-branch-is-tracking

Find out which remote branch a local branch is tracking

$ git branch -vv
  main   aaf02f0 [main/master: ahead 25] Some other commit
* master add0a03 [jdsumsion/master] Some commit
Using Git with Ungit
http://blog.goguardian.com/nerds/ungit-the-easiest-way-to-use-git

https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration
If you don’t want to type it every single time you push, you can set up a “credential cache”. The simplest is just to keep it in memory for a few minutes, which you can easily set up by running git config --global credential.helper cache.
https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration
http://stackoverflow.com/questions/2003505/delete-a-git-branch-both-locally-and-remotely
git branch -d the_local_branch
git push origin --delete <branchName>
which is easier to remember than
git push origin :<branchName>
http://stackoverflow.com/questions/520650/make-an-existing-git-branch-track-a-remote-branch
Or, if local branch foo is not the current branch:
git branch -u upstream/foo foo
Or, if you like to type longer commands, these are equivalent to the above two:
git branch --set-upstream-to=upstream/foo

git branch --set-upstream-to=upstream/foo foo

core.editor

git config --global core.editor emacs

https://medium.freecodecamp.com/towards-better-git-commit-messages-using-atom-6dbda5e14984
git config --global core.editor "atom --wait"
git config --get core.editor
# Which should give you the output: atom --wait
Atom snippet:
'.text.git-commit':
  'commit-message':
    'prefix': 'comm'
    'body': """
      ${1:Subject < 50 chars}
      ${2:Body in detail}
    """

https://medium.freecodecamp.com/7-git-hacks-you-just-can-t-ignore-41aea137727a
$ git commit --amend -m ”YOUR-NEW-COMMIT-MESSAGE”
3. Undo your most recent commit
$ git reset --soft HEAD~1
# make changes to your working files as necessary
$ git add -A .
$ git commit -c ORIG_HEAD

4. Revert your git repo to a previous commit
‘Reverting’ can make a lot of senses in a many cases — especially if you’ve completely messed up a piece of code. The most common case is when you want a go back in time and explore a previous state of your codebase, then return back to your present state.

git checkout <SHA>
It will detach the HEAD, and let you fool around with no branch checked out. Don’t worry — detaching your head is not as scary as it sounds. If you want to make commits while you’re here, you can do so by creating a new branch here:
$ git checkout -b <SHA>
To go back to the present state, just checkout to the branch you were on previously.
Stack Overflow answer

7. Delete a Git branch both locally and remotely
To delete a local branch:
$ git branch --delete --force <branchName>
# OR use -D as a short-hand:
$ git branch -D
To delete a remote branch:
$ git push origin --delete <branchName>
https://medium.freecodecamp.com/understanding-git-for-real-by-exploring-the-git-directory-1e079c15b807
├── HEAD
├── branches
├── config
├── description
├── hooks
│ ├── pre-commit.sample
│ ├── pre-push.sample
│ └── ...
├── info
│ └── exclude
├── objects
│ ├── info
│ └── pack
└── refs
 ├── heads
 └── tags
Every-time you create a file, and track it, git compresses it and stores it into its own data structure. The compressed object will have a unique name, a hash, and will be stored under the object directory.

What’s inside a commit ?

Every-time you create a file, and track it, git compresses it and stores it into its own data structure. The compressed object will have a unique name, a hash, and will be stored under the object directory.
Before exploring the object directory we’ll have to ask ourselves what is a commit. So a commit is kind of a snapshot of your working directory, but it is a little bit more than that.
In fact when you commit git does only two things in order to create the snapshot of your working directory:
1. If the file didn’t change, git just adds the name of the compressed file (the hash) into the snapshot.
2. If the file has changed, git compresses it, stores the compressed file in the object folder. Finally it adds the name (the hash) of this compressed file into the snapshot.
This is a simplification, this whole process is a little bit complicated and will be part of a future post.
And once that snapshot is created, it will also be compressed and be name with an hash, and where all those compressed objects end up ? In the object folder.
├── 4c
│ └── f44f1e3fe4fb7f8aa42138c324f63f5ac85828 // hash
├── 86
│ └── 550c31847e518e1927f95991c949fc14efc711 // hash
├── e6
│ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391 // hash
├── info // let's ignore that
└── pack // let's ignore that too
This is what the object directory looked like after I created one empty file file_1.txt and commited it. Please note that if the hash of your file is “4cf44f1e…”, git will store this file under a “4c” subdirectory and then name the file “f44f1…”. This little trick reduces by 255 the size of the /objects directory.
You see 3 hash right. So one would be for my file_1.txt, the other would be for the snapshot created when I commited. What is the third one ? Well because a commit is an object in itself, it is also compressed and stored in the object folder.
What you need to remember is that a commit is made of 4 things :
  1. The name (a hash) of the working directory’s snapshot
  2. A comment
  3. Commiter information
  4. Hash of the parent commit
And that’s it, look by yourself what happen if we uncompressed the commit file :
// by looking at the history you can easily find your commit hash
// you also don't have to paste the whole hash, only enough 
// characters to make the hash unique
git cat-file -p 4cf44f1e3fe4fb7f8aa42138c324f63f5ac85828
This is what I get
tree 86550c31847e518e1927f95991c949fc14efc711
author Pierre De Wulf <test@gmail.com> 1455775173 -0500
committer Pierre De Wulf <test@gmail.com> 1455775173 -0500
commit A
You see, we got as expected, the snapshot hash, the author, and my commit message. Two things are important here :
  1. As expected, the snapshot hash “86550…” is also an object and can be found in the object folder.
  2. Because it was my first commit, there is no parent.
What’s in my snapshot for real ?
git cat-file -p 86550c31847e518e1927f95991c949fc14efc711
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file_1.txt
And here we find the last object that was previously in our object store, the only object that was in our snapshot. It’s a blob, but that’s another story.

branch, tags, HEAD all the same

So now you understand that everything in git can be reached with the correct hash. Let’s take a look at the HEAD now. So what’s in that HEAD?
cat HEAD
ref: refs/heads/master
Okay, this is not an hash, and it makes sense, because the HEAD can be considered as a pointer to the tip of the branch you’re working on. And now if we look at what is in refs/heads/master here what we’ll see :
cat refs/heads/master
4cf44f1e3fe4fb7f8aa42138c324f63f5ac85828
Does that look familiar? Yes this is the exact same hash of our first commit. This shows you that branches and tags are nothing more than a pointer to a commit. Meaning that you can delete all the branches you want, all the tags you want, the commit they were pointing to are still going to be here. There are only be much more difficult to access.
https://medium.freecodecamp.com/git-rebase-and-the-golden-rule-explained-70715eccc372
git-rebase: Reapply all the commit from your branch to the tip of another branch.
A rebase will sequentially take all the commit from the branch you’re in, and reapply them to the destination. This behavior has 2 main implications:
  1. By reapplying commits git creates new ones. Those new commits, even if they bring the same set of change will be treated as completely different and independent by git.
  2. Git rebase reapplies commits, and does not destroy the old ones. It means that even after a rebase, your old commits will still be in the /objects folder in your .git directory. If you are not really familiar with how git consider and stores commit you could learn some interesting things here.
So this could be a more accurate representation of what actually happens during a rebase:




























As you can see, the feature branch has completely new commits. As said before, same set of changes, but completely different objects from the git point of view. And you can also see that previous commits are not destroyed. They are simply not directly accessible. If you remember, a branch is only a pointer to a commit. Therefore if neither branches nor tags are pointing to a commit it becomes almost impossible to reach, but the commit still exists.

The golden rule of rebase

“No one shall rebase a shared branch” — Everyone about rebase
You have probably came across that rule, maybe phrased differently. For those who haven’t, this rule is quite simple. Never, NEVER, NEVER, rebase a shared branch. By shared branch I mean a branch that exists on the distant repository and that other people on your team could pull.
Too often this rule is thrown as a divine truth and I think understanding it could be a good thing if you want to improve your understanding of git.
To do that, let’s imagine a situation where a dev breaks the rule and see what happens.
Let’s say Bob and Anna are both working on the same project. Here is an overview of both Bob’s, Anna’s repos and the remote on GitHub:




























Everybody is sync with the remote (GitHub)
Now Bob, innocently breaks the golden rule of rebase, in the mean time Anna decides to work on the feature and creates a new commit:




























Do you see what’s coming ?
Bob tries to push now, he got rejected and receives that kind of message:




























Oh My Zsh with agnoster theme for those who cares

Here git is not happy because it doesn’t know how to merge the Bob feature branch with the GitHub feature branch. Usually when you push your branch on the remote, git merges the branch you’re trying to push with the branch currently on the remote.
Before the pull those are the commits in the distant and local feature branch:
A--B--C--D'   origin/feature // GitHub
A--B--D--E    feature        // Anna
When you pull, git has to do a merge to resolve this issue. And this is what happens:




























The commit M represent the merge commit. The commit where Anna’s and GitHub’s feature branch were finally reunited. Anna is finally relieved, she managed to resolve all the merge conflicts and can now push her work. Bob decides to pull, and everyone is now synced.

https://github.com/tiimgreen/github-cheat-sheet
Git Grep will return a list of lines matching a pattern.
$ git grep aliases
-e The next parameter is the pattern (e.g. regex)
--and, --or and --not Combine multiple patterns.
 $ git grep -e pattern --and -e anotherpattern

 Git Stripspace:
 Strips trailing whitespace
 Collapses newlines
 Adds newline to end of file
 A file must be passed when calling the command, e.g.:
 $ git stripspace < README.md

git status -sb
Auto-Correct
To call commit when comit is typed, just enable auto-correct:
$ git config --global help.autocorrect 1

To add more color to your Git output:
$ git config --global color.ui 1

https://github.com/thoughtbot/guides/tree/master/protocol/open-source
Given you have this in your ~/.gitconfig:[alias] co-pr = !sh -c 'git fetch origin pull/$1/head:pr/$1 && git checkout pr/$1' -

Check out the code by its GitHub pull request number:git co-pr 123
Rebase interactively, squash, and potentially improve commit messages:git rebase -i master
https://github.com/thoughtbot/guides/tree/master/protocol/git
  • Avoid including files in source control that are specific to your development machine or process.
  • Delete local and remote feature branches after merging.
  • Perform work in a feature branch.
  • Rebase frequently to incorporate upstream changes.
  • Use a pull request for code reviews.

Create a local feature branch based off master.

git checkout master
git pull
git checkout -b <branch-name>
Rebase frequently to incorporate upstream changes.
git fetch origin
git rebase origin/master
Resolve conflicts. When feature is complete and tests pass, stage the changes.
git add --all
When you've staged the changes, commit them.
git status
git commit --verbose
Write a good commit message. Example format:
Present-tense summary under 50 characters

* More information about commit (under 72 characters).
* More information about commit (under 72 characters).

http://project.management-system.com/ticket/123
If you've created more than one commit, use git rebase interactively to squash them into cohesive commits with good messages:
git rebase -i origin/master
Share your branch.git push origin <branch-name>

Rebase interactively. Squash commits like "Fix whitespace" into one or a small number of valuable commit(s). Edit commit messages to reveal intent. Run tests. git fetch origin git rebase -i origin/master

Force push your branch. This allows GitHub to automatically close your pull request and mark it as merged when your commit(s) are pushed to master. It also makes it possible to find the pull request that brought in your changes. git push --force-with-lease origin <branch-name>

View a list of new commits. View changed files. Merge branch into master. git log origin/master..<branch-name> git diff --stat origin/master git checkout master git merge <branch-name> --ff-only git push

Delete your remote feature branch. git push origin --delete <branch-name>

Delete your local feature branch. git branch --delete <branch-name
https://help.github.com/articles/about-git-rebase/
The git rebase command allows you to easily change a series of commits, modifying the history of your repository. You can reorder, edit, or squash commits together.
Typically, you would use git rebase to:
Edit previous commit messages
Combine multiple commits into one
Delete or revert commits that are no longer necessary
http://kentnguyen.com/development/visualized-git-practices-for-team/Branch out, merge often, keep in sync
  • You are about to make a major or disruptive change
  • You are about to make some changes that might not be used
  • You want to experiment on something that you are not sure it will work
  • When you are told to branch out, others might have something they need to do in master
After branching out, you should keep in-sync with the master branch, because eventually you need to merge it back to master. In order to avoid a huge complicated mess of conflicts when merging back, you should commit often, merge often.
(on current branch) git rebasing is taking all your local changes since the last push and put them ahead of other people’s changes regardless of the date you made the commit.
Base on that, git pull --rebase means pulling all the new changes made by others, then taking all my changes that are not yet pushed, and put them ahead of other people’s changes on the current branch.
http://stackoverflow.com/questions/6188591/download-github-pull-request-as-unified-diff
To view a commit as a diff/patch file, just add .diff or .patch to the end of the URL, for example:
the diff command is used to compare differences between two versions of a file. The resulting file is called a patch, and typically is given (by the user) a ".patch" or ".diff" suffix.
This patch file then can be used on other copies of the "old" file by using the patch command, thus updating their "old" file(s) to match the "new" file(s).
This will create a new file fix_empty_poster.patch with all changes from the current (fix_empty_poster) against master. Normally, git would create a separate patch file for each commit, but that’s not what we want. All we need is a single patch file.
git apply --stat fix_empty_poster.patch
Note that this command does not apply the patch, but only shows you the stats about what it’ll do. After peeking into the patch file with your favorite editor, you can see what the actual changes are.
To apply the patch, I’ll use git am instead of git apply. The reason for this is that git am allows you to sign off an applied patch. This may be useful for later reference.
git am --signoff < fix_empty_poster.patch
Applying: Added specs to test empty poster URL behaviour
Applying: Added poster URL as part of cli output
git apply [patch-name].patch
You can reverse a patch if you have finished testing. To reverse the patch, use the patch command with the -R option: git apply -R path/file.patch

git apply --check a.patch

http://codepub.cn/2015/05/14/Git-filtering-method-of-uploaded-files/

编写.gitignore规则文件的两种模式

两种模式分别是开放模式和保守模式
① 开放模式负责设置过滤哪些文件和文件夹
过滤文件夹设置:
/mtk/ 表示过滤这个文件夹
过滤文件设置:













1
2
3
*.zip
*.rar
*.err

指定过滤某个文件:
/mtk/do.doc
② 保守模式负责设置哪些文件不被过滤,也就是哪些文件要跟踪
跟踪某个文件夹:
!/people/master
跟踪某类文件:













1
2
!*.c
!*.h

跟踪某个指定文件:
!/people/master/IT.h
采用共享模式与保守模式结合配置的办法。eg:一个文件夹下有很多文件夹和文件,而我只想跟踪其中的一个文件,这样设置就可以满足这种情况,先用共享模式把整个目录 都设置为不跟踪,然后再用保守模式把这个文件夹中想要跟踪的文件设置为被跟踪,配置很简单,就可以跟踪想要跟踪的文件。

.gitignore文件失效问题

比如在一个本地仓库中,产生了诸多的日志记录,而这些记录都是本地操作产生的,我们不必将其提交到远程仓库中,那么我们在.gitignore中添加了logs/20150514.log的过滤规则,但是在使用git status的时候,还是可以看到modified:logs/20150514.log,说明规则没有起作用。
为什么增加了.gitignore里的规则却没有效果呢?
这是因为.gitignore文件只能作用于Untracked Files,也就是那些从来没有被Git记录过的文件(自添加以后,从未add及commit过的文件)。
之所以规则不生效,是因为那些.log文件曾经被Git记录过,因此.gitignore对它们完全无效,解决办法如下:
  • 从Git的数据库中删除对于该文件的追踪;
  • 把对应的规则写入.gitignore,让忽略真正生效;
  • 提交+推送
只有这样做,所有的团队成员才会保持一致而不会有后遗症,也只有这样做,其他的团队成员根本不需要做额外的工作来维持对一个文件的改变忽略。
最后有一点需要注意的,git rm —cached logs/20150514.log 删除的是追踪状态,而不是物理文件;如果你真的是彻底不想要了,你也可以直接 rm+忽略+提交。

全局设置排除文件

全局设置排除文件,这会在全局起作用,只要是Git管理的工程,在提交时都会自动排除不在控制范围内的文件或目录。这种方法对开发者来说,比较省事,只要一次全局配置,不用每次建立工程都要配置一遍过滤规则。但是这不保证其他的开发者在克隆你的代码后,他们那边的规则跟你的是一样的,这就带来了代码提交过程中的各种冲突问题。配置步骤如下:
① 同样需要建立一个.gitignore文件,把要排除的文件写进去。但在这里,我们不规定一定要把.gitnore文件放到某个工程下面,而是任何地方,比如我们这里放到了Git默认的Home路径下,在我的
windows上就是C:\Users\yourusername。使用命令方式可以配置全局排除文件













1
git config --global core.excludesfile ~/.gitignore

你会发现在~/.gitconfig文件中会出现excludesfile = C:/Users/yourusername/.gitignore。说明Git把文件过滤规则应用到了Global的规则中。

Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts