Showing posts with label git. Show all posts
Showing posts with label git. Show all posts

Saturday, May 18, 2019

The Conceptual Model, the Key to Understanding Git

From Pluralsight course "How Git Works"
 
If you don't want to get into trouble, understand the conceptual model.
 
Layers:
Distributed revision control
Revision control system
Stupid content tracker
Persistent map (the core)
 
The entire object model:
Blobs
Trees
Commits
Annotated tags
 
A commit is a SHA'd object that stores the SHAs of trees and blobs as well as the parent commit, author and date and commit message.
 
A branch is just a reference to a commit. Nothing more.
 
HEAD is just a reference to a branch. Or a reference to a commit if you checked out a commit, in this case the HEAD is a detached HEAD.
 
Checkout changes HEAD to point to the branch being checked out, and the working area is changed to the files represented in the commit referenced in the branch object.
 
A tag is like a branch that doesn't move.
 
Detached HEAD:
Checkout any commit. Now you can work in a "detached way" like a spike. If you don't create a branch off a detached commit Git will garbage collect all the detached commits eventually.
 
Three Rules:
1) The current branch tracks new commits.
2) When you move to another commit, Git updates your working directory.
3) Unreachable objects (those that are not reachable via a branch, HEAD or a tag) are garbage collected.
 
Rebase:
When in doubt, just merge. Only rebase if you know what you're doing and are fully aware of any consequences.
 
 
 
Command reference:
git show-ref <branch>       this will show the contents of the branch file which is a reference to a commit but will show both the local branch and remote so you can see if there is a difference. If the commits are the same, then the local and remote are synchronized.
 
git cat-file -p <sha>
to show contents of a commit. Don’t need to be in the objects subdirectory.
But you do need to put the 2 char folder name as prefix to the file name
 

Monday, February 11, 2019

Git in Visual Studio 2017

Created new empty project in Git except for .gitignore file. No readme file was created.
Cloned in VStudio, and in master added a new test project.
The remote master history only shows the .gitignore add, as expected.
The local master history has same because no commits yet.
Now to commit and push to master by:
Commit All
Then switch to branches view and right click on local master and Push
This sent the new project to the remote master.
Created new local folder (VSGit2) for a second copy of VSGit repo, and cloned it from second instance of VS (we'll call this repo2 for this post)
Created a new branch "branchOne" of local master in repo1
Added a readme to remote master from GitHub interface and checked in to master. I verified this by viewing history in master from GitHub site.
But remote/master history from VS does not show the readme file.
 
Scenario:
Added a readme to remote master from GitHub interface.
Exercise: download and merge that readme file into local branchOne.
First lets bring down latest from remote/master to local master:
From local master, did a Fetch from VS. History now shows incoming readme.
Did a Pull, history now shows readme commit under "Local History."
And now VS remote master history shows the same thing.
branchOne does not have readme yet because that file was added to master in GitHub.
From merge dropdown/dialog, selected local master to merge to branchOne, unchecked commit.
Got a message saying I needed to commit. In changes area, I see the readme and I clicked "Commit Staged."
Scenario exercise completed.
 
branchOne is same now as local and remote master.
 
Moving to repo2, I do not see branchOne in remotes/origin, even after clicking refresh.
A history of remote/master does not show the readme commit.
 
Scenario:
repo1 now is up to date with master, now make repo2 up to date also, this time experimenting with the "Sync" functionality.
Exercise: Sync repo2 and see what happens, or "get latest"
Well, there is no Sync option.
Right-clicked on local master and Fetched. History now shows the incoming readme.
Pulled. History now shows readme, but no branchOne in local area. I do see it in remotes area.
Right clicked branchOne in remotes and selected "Checkout."
Now I see it in local. History does not show readme commit.
I could do a fetch and pull, but let's try a merge from local master which has all commits to local branchOne and keep commit checkbox checked.
Now readme file shows on file system and history shows all commits.
Scenario exercise completed.
 
History of remote/master shows all commits. I never had to fetch (I think, see above). I assume I could have or maybe should have. If so, then this merge and a fetch/pull does the same thing?
 
Scenario:
Bob (repo1) makes a change to branchOne's VSGitTestOne class. Then Bob commits and pushes and then creates a pull request that gets merged to master.
Meanwhile, Joe in repo2 has created a new local branch "feature1." Joe creates a new test class VsGitTestThree and commits locally only. 
Exercise: Joe in repo2 wants to keep working in feature1 but wants to merge Bob's work into his branch before continuing. So he must merge master into feature1.
Joe switches his local to master and fetches then pulls. History shows Bob's change and also the merge of his PR 3 to master.
Joe checks out feature1 branch and merges from master with commit after checked. feature1 history now shows all the master history plus its own commit of merge from local master.
Scenario exercise completed.
 
Bob and Joe are done with their branches.
 
Scenario:
Simulate Microsoft's release/deployment/hotfix branching strategy. See if this can be done without Azure.
Setup - release branch | PRx | hotfix PR | PRy and "cherry pick" merge of hotfix to release:
Bob and Joe are merged to remote master and it's the end of the sprint so let's create a release or deployment branch M1 off master:
In VStudio (didn't see how to do this in GitHub) did a fetch/pull on master to sync local from server. Then created branch releases/M1 w/ checkout. Then right clicked and Push Branch which brought it up to server.
Bob creates bobFeature1 branch off master and commits/pushes and pull requests to master.
An embarrassing typo is found and Bob creates bobTypo1 branch off master and fixes it, commits/pushes/pull requests, PR gets merged to master.
Joe creates joeFeature2 and commits/pushes/pull requests, PR gets merged to master. He does this without merging Bob's typo change, but there was no conflict during the pull request merge. (but somehow, Bob's typo change got into Joe's joeFeature2 branch. I didn't see when, maybe during the pull request?)
So now we have 3 PR's and we want to cherry pick the middle one into the M1 release branch.
 
 
 
from local branchOne, pull down that master change (new readme file)
While in branchOne, in Branches area in TS I pulled down the Merge link/dropdown and it brought up a merge dialog. In "Merge from branch:" box I selected local master. I got the message "Already up to date."
So I selected origin/master and unchecked "Commit changes after merging."
Again, "Already up to date."
Maybe merging
 
 
(no) I think the merge functionality is to merge between different branches, not the same branch.
 
Tried to create PR, but got "No commits between master and branchOne" which means nothing to merge into master from branchOne.
From local master, did a Fetch from VS. History now shows incoming readme.
Did a Pull, history now shows readme commit under "Local History."
And now VS remote master history shows the same thing.
 
 
Commit All - local only
Commit All and Push - local and push to remote
Commit All and Sync - local and push to remote and pull down any changes
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Saturday, September 17, 2016

New Project Connected to BitBucket Git Repo

(Using a Web API project)
 
Create project in VS2015 selecting "Create new Git repository" checkbox.
 
Click on Team Explorer Home toolbar button.
 
Click on Sync button.
 
Create repo in BitBucket.
 
Under "Publish to Remote Repository", click "Publish Git Repo"
 
Get URL to BB repo under Command Line link "I'm starting from scratch"
 
Paste then click "Publish"
 
Now click Sync, and with little or no indication of any progress you should see the files in BB.
 
You can change a file and check in then sync and it should appear in BB (or actually, I think you may need to put a change in, not sure)
 
 
 
 
 
 
 

Sunday, September 6, 2015

Git Setup and Configuration

Configuring git for KDiff3
Add to .gitconfig (located C:\Users\Tim):

[diff]
    tool = kdiff3
[difftool]
    prompt = false
[difftool "kdiff3"]
    path = C:/Program Files/KDiff3/kdiff3.exe
    trustexitcode = true
[merge]
    tool = kdiff3
[mergetool "kdiff3"]
    path = C:/Program Files/KDiff3/kdiff3.exe
    keepbackup = false
    trustexitcode = true

then run it using >git difftool .\folder\Web.config
yes, using quotes to deal with the spaces in program files in .gitconfig file screws it up. Don't use quotes.

Using Console2
Scott Hanselman's blog post
I put a copy of the Console config file in SpiderOak under Dev/Git.

Powershell Execution Policy
Stackoverflow
Set-ExecutionPolicy Unrestricted -Scope CurrentUser -Force


Making Powershell Readable
add to .gitconfig
[color]
    ui = true
[color "status"]
    changed = red bold reverse
    untracked = red bold reverse
    added = green bold
[color "branch"]
    current = green bold
(see copy of config file in SpiderOak)

Credential Caching
Avoid having to enter password
http://gitcredentialstore.codeplex.com/ (just install it, and it will prompt you once, then you're good)

Links
Getting set up in a new environment (git w/ PShell, PsGet, Posh-Git)
Must-have git aliases

[user]
 email = ttonnesen@gmail.com
 name = Tim


My aliases (not all work):

[alias]
s = status
c = commit -m
a = add
co = checkout
br = branch
sh = stash
dt = difftool
pb = push origin

# short log
logsimp = log --oneline --decorate
logSimpFiles = log --pretty=format:"%h%Cred%d\\ %Creset%s%Cgreen\\ [%cn]" --decorate --numstat
logSimpDates = log --pretty=format:"%C(yellow)%h\\ %ad%Cred%d\\ %Creset%s%Cgreen\\ [%cn]" --decorate --date=short
logSimpAge = log --pretty=format:"%C(yellow)%h\\ %ad%Cred%d\\ %Creset%s%Cgreen\\ [%cn]" --decorate --date=relative

comp = difftool --dir-diff
#DoesntWork: compcommits = "!f() { git difftool "$1"^.."$1"; }; f"
# Same as compare-by-changeset but shows all files in directory. For ex: git lsf (shows commit changeset numbers) then git dcd 85a7f8b
#ProbDoesntWork: compare-by-changeset-directories  = "!f() { git difftool --dir-diff "$1"^.."$1"; }; f"

# list aliases to console
list-aliases = "!git config -l | grep alias | cut -c 7-"

# git stash show -p 'stash@{0}' shows tracked files that were stashed, but not untracked, the &&'d command shows untracked
stash0-show = !git stash show -p 'stash@{0}' && git ls-tree -r 'stash@{0}^3'
stash1-show = !git stash show -p 'stash@{1}' && git ls-tree -r 'stash@{1}^3'

Monday, January 19, 2015

Git Workflow

Workflow
git status
new files will be listed as "Untracked files:" and use git add to put them into the repo as staged
git add *   (stages all, seems to do the same as git add --all)
git add .  (stages new and modified without deleted files)
git add -u  (stages deleted and modified without new files)
git add .\folder\filename.txt
git commit -m "message"
commit to remote repo
git push origin <branch>
git push -u origin <branch>    (push new local branch not yet on remote. -u short for --set-upstream)

Merge branch to master:
git checkout master
git pull origin master
git merge <branch>
git push origin master
git branch -d mybranch    (deletes mybranch locally only)
git push origin -d mybranch    (deletes remote mybranch)

git fetch origin  (makes the local tracking branch up to date of the current branch, does NOT modify working directory)
git merge origin/master

git checkout dev  (DWIM version that will create a local branch dev and if dev exists on remote it will set up a tracking branch for it.)

Push to master
git push origin master

Diff
git difftool .\folder\Web.config      (compares local to remote, you may not need the leading .\)
git difftool --dir-diff .\SportsStore\SportsStore  (all changes in this and subfolders, except deletes I think)
git difftool --dir-diff master origin/master  (Will not do anything including not launching diff UI if local matches remote)
git difftool d60f4cf..8d6e908 compares commits. If > 1 file is in the result, you will be prompted, so escape out of compare tool to get to the next file. A caret ^ before the .. (git difftool d60f4cf^..8d6e908) has a different behavior, not sure what that is.

Log
git log --oneline       (git logsimp using alias)
git log --oneline ./src/main/mule/training4-american2-ws.xml

this is the same as git logSimp   (using alias):
        git log --pretty=format:"%h - %an: %s" --shortstat
git logsimp -5     (returns the last 5 log entries)

Log using aliases:
git logsimp
git logsimpfiles
git logsimpdates
git logsSmpAge


History of a file (last 5 checkins)
git lsf -5 .\SportsStore\SportsStore.Tests\IocTests.cs
Now you can view the diff by changeset
git dcd f028a41
 
Aliases
git list-aliases (this is an alias...)

Branching and Working with Branches
git branch (shows local branches)
git branch -r (remote tracking branches)
git branch -a (remote and local branches)
git branch -vv (lists local branches and their mapped remote tracking branch. If working directory is ahead 3 checkins then it will say that next to the remote branch, and after the remote branch's closing bracket ] it will show the last checkin message from the remote server. All info is based on last fetch from server.)
git show-branch --all  (shows any checkins that are ahead of remote, then the remote branch)
git branch -d mybranch    (deletes mybranch locally only)

git push origin -d mybranch    (deletes remote mybranch)
git push -u origin <branch>    (push new local branch not yet on remote. -u short for --set-upstream)

Create a new branch from master
Get local in sync with remote.
git branch dev (does not create a corresponding remote tracking branch, which means another developer won't see it and you can't push to remote using git push --all when in dev branch.)
Then do:
git push -u origin dev. Now other developers will be able to do a git fetch origin and then git checkout dev and see the changes you made in dev branch.

Switching to other branch(es)
If you make a change in master w/out staging it or checking it in and you do a checkout to dev branch, one of 2 things can happen:
1) You will get an error message saying you might lose your changes in master.
2) You will be checked out to dev but the dirty files will now be in the dev branch.
Scenario 2 seems dangerous and I don't know why git doesn't consistently throw an error. Seems a bad choice to just allow those changes into the other branch's working directory.

If I have unstaged or staged files in master and I want to switch to dev without checking in to HEAD my changes in master, I can do:
git stash -u   (stashes unstaged files in working dir)
and now you can do
git co dev  and you'll be good

** caution - doing a stash, then making more changes and doing yet another stash so you have 2 stashes when you do a list can cause problems when you go to pop the second time. You may get a merge error. So don't stash more than once. (well, sort of, I got the error, then did a drop and the untracked file in the first stash got restored. KISS, only one stash.)

git stash pop  (takes latest stash, stash@{0} and restores it. Do it again and it restores the next in the stack)
git stash apply  (caution, I think the stash may persist...)
git stash list   (to see what you have stashed)
git stash drop  (deletes the stash at the top of the stack and you lose those changes, sort of, see caution above.)



Fetching/Merging
if a branch "serverfix" was created by a co-worker and he pushes it onto the server, and you do a [git fetch origin], this fetch creates a reference (this is a remote-tracking branch) to where the serverfix branch is: origin/serverfix. This does not bring any files down that you can work on, you have to do a checkout for that. So at this point, without doing a checkout yet, with the fetch we've only created locally a remote tracking branch for serverfix.
So it's like the relationship I got after doing my clone with master and origin/master. The clone, however did bring files down and at the same time created the remote tracking branch.
git checkout -b serverfix origin/serverfix
-- this will download files from server (origin) and switch (don't know how switch works) to the new branch serverfix. I hope that a new folder is created. I'm sure it does, the "switch" means that git now is in the context of serverfix, not master on the local machine. So if I work on files on my file system that map to master, then (I think) my powershell will not track any work I do there, it is only looking at serverfix changes.
So what the above checkout command does is "checks out a local branch from a remote-tracking branch"

Move to new folder
I had a VS solution that was in c:\TestGit\TestBootstrap\TestBootstrap
This folder had the root of the solution (however the .sln file was in c:\TestGit\TestBootstrap
I wanted to have the new folder structure be c:\TestGit\TestBootstrap\trunk\src
So I added to my local the trunk and src folders with a temp file in there so it would actually get into git.

do a 'git add *' (puts the folders into git staging)

do a 'git mv -n' first for a preview

git mv  -n TestBootstrap/TestBootstrap TestBootstrap/trunk/src
The above command worked from repo root of c:\TestGit.

Don't forget to delete the temp file.

Links

Test/learning scenarios
================
Scenario - Check-in Dance:
Branch master is like trunk, we don't work there, we merge changes from dev branch mainly. This scenario says do some work in dev, check it into remote, then merge it to master. Then have co-worker download changes in both.
git fetch origin
git merge origin/<branch>
co-worker does same

Scenario - Undoing:
Revert all local uncommitted changes (should be executed in repo root):
git checkout .

Unstage all files you might have staged with git add:
git reset

Revert uncommitted changes only to particular file or directory:
git checkout [some_dir|file.txt]

Yet another way to revert all uncommitted changes (longer to type, but works from any subdirectory):
git reset --hard HEAD

Undo working directory changes (unstaged changes):
git checkout -- . (replaces working directory with what is in index. Will restore deletes.)
Caution, stashing doesn't play nice with deleted files.
git stash -u  (understand what stash does before using)
git stash


Scenario - Merge master to dev: Change made in master branch after dev branch was created from master. All changes in both branches are pushed to remote repo. This scenario says we should only work from dev branch, so we need to now merge master up to dev.
~merge master into dev~ dev
git checkout dev
git merge master

Scenario - Conflicts: Two coworkers are totally in sync with remote and have not yet made any changes. Then they both change the same line on the same file and check in and push to master. What happens? How do you resolve this?
So coworker A pushes his change to remote successfully. B commits his but when attempting to push to origin gets an error and it won't let him. So B has to do a fetch and merge and git will tell him there is a conflict and he'll have to resolve it. Whatever the resolution the next step for B is to push to origin and then A can do a fetch/merge.
** But alas, we must always do the check-in dance -- first do a fetch and merge, and deal with the conflict locally.

Scenario - Working in Wrong Branch: I thought I was working in dev branch but instead I was in master and made enough changes to not want to lose them or to manually move them.
So basically, I want to move changes in my master branch working directory to the dev branch working directory.
  • So we are in master branch.
  • git stash list (make sure there aren't any other stashes, or of so, keep track so you know what's what)
  • git stash -u (see above)
  • git stash list (see the new stash
  • git co dev
  • git stash list
  • git stash pop (now those changes get applied to dev)
Scenario - Add your code to a new repository: I created a new BitBucket repo, then I created a new VStudio or Android project, now I want to add the project into the new remote repo.
 
(see below if you are doing something like cloning from someone else's GitHub, then wanting to add it to a new BitBucket repo)
  • There is a link on BitBucket's repo page to do this just after you create the repo in BB: "I starting from scratch " (something like that)
  • Navigate console to root of project on local machine
  • git init
  • git remote add origin https://ttonnesen@bitbucket.org/ttonnesen/maplauncher-web.git
  • git add --all
  • git ci -m "initial checkin"
  • git push origin master
From GitHub to BitBucket:
  • Delete the git files from the root of the project (except for maybe the gitignore)
  • You are going to do a git clone of your new BitBucket repo, so it will download a folder and inside that folder will be the git files, so the repo will be inside that folder, so decide where that downloaded file will live. You can always move it after you do the clone.
  • Now throw the files you cloned from GitHub into that new folder you cloned down from BitBucket.
  • git add --all
  • git ci -m "initial checkin"
  • git push origin master