2017年8月30日 星期三

[ Git 常見問題 ] Can't push to branch after rebase

Source From Here 
Question 
We use git and have a master branch and developer branches. I need to add a new feature and then rebase the commits to master, then push master to CI server. 

The problem is that if I have conflicts during rebase I cannot push to my remote developer branch (on Github) after the rebase is complete, until I pull my remote branch. This causes duplicate commits. When there are no conflicts, works as expected. 

Question: after rebase and conflict resolution, how do I sync up my local and remote developer branches without creating duplicate commits 
Setup: 
  1. // master branch is the main branch  
  2. git checkout master  
  3. git checkout -b myNewFeature  
  4.   
  5. // I will work on this at work and at home  
  6. git push origin myNewFeature  
  7.   
  8. // work work work on myNewFeature  
  9. // master branch has been updated and will conflict with myNewFeature  
  10. git pull --rebase origin master  
  11.   
  12. // we have conflicts  
  13. // solve conflict  
  14. git rebase --continue  
  15.   
  16. //repeat until rebase is complete  
  17. git push origin myNewFeature  
  18.   
  19. //ERROR  
  20. error: failed to push some refs to 'git@github.com:ariklevy/dropLocker.git'  
  21. hint: Updates were rejected because the tip of your current branch is behind  
  22. hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')  
  23. hint: before pushing again.  
  24. hint: See the 'Note about fast-forwards' in 'git push --help' for details.  
  25.   
  26. // do what git says and pull  
  27. git pull origin myNewFeature  
  28.   
  29. git push origin myNewFeature  
  30.   
  31. // Now I have duplicate commits on the remote branch myNewFeature  
How-To 
First, you and those you're working with need to agree whether a topic/devel branch is for shared development or just your own. Other developers know not to merge on my development branches because they'll be rebased at any time. Usually the workflow is as follows: 
  1. o-----o-----o-----o-----o-----o       master  
  2. \  
  3.    o-----o-----o                      devel0  
  4.                 \  
  5.                   o-----o-----o       devel1  
Then to stay up-to-date with remote I'll do the following: 
# git fetch origin 
# git checkout master 
# git merge --ff origin/master

I do this for two reasons. First because it allows me to see if there are remote changes without needing to switch from my devel branch. Second it's a safety mechanism to make sure I don't overwrite any un-stashed/committed changes. Also, if I can't fast-forward merge to the master branch that means either someone has rebased the remote master (for which they need to be flogged severely) or I accidentally committed to master and need to clean up my end. 

Then when remote has changes and I've fast forwarded to the latest I'll rebase: 
# git checkout devel0 
# git rebase master 
# git push -f origin devel0

Other developers then know they'll need to rebase their devel branches off my latest: 
# git fetch  
# git checkout devel1 
# git rebase /devel0

Which results in much cleaner history: 
  1. o-----o                                 master  
  2.        \  
  3.          o-----o-----o                  devel0  
  4.                       \  
  5.                         o-----o-----o   devel1  
Don't merge commits back and forth at your whim. Not only does it create duplicate commits and make history impossible to follow, finding regressions from a specific change becomes near impossible (which is why you're using version control in the first place, right?). The problem you're having is the result of doing just this. 

The only time to merge is when your topic branch is ready to be accepted into master. On a side note. If multiple developers are committing to the same repository you should all consider having named branches to distinguish between developers devel branches. For example: 
# git branch 'my-name/devel-branch'

This message was edited 7 times. Last update was at 30/08/2017 21:53:53

[ Git 常見問題 ] Git merge master into feature branch

Source From Here 
Question 
Lets say we have the following situation in git: 
1. A created repository: 
# mkdir GitTest2
# cd GitTest2
# git init

2. Some modifications in the master take place and get committed. 
# echo "On Master" > file
# git commit -a -m "Initial commit"

3. Feature1 branched off master and some work is done: 
# git branch feature1
# git checkout feature1
# echo "Feature1" > featureFile
# git commit -a -m "Commit for feature1"

4. Meanwhile, a bug is discovered in the master-code and a hotfix-branch is established 
# git checkout master
# git branch hotfix1
# git checkout hotfix1

5. The bug is fixed in the hotfix branch and merged back into the master (perhaps after a pull request/code review): 
# echo "Bugfix" > bugfixFile
# git commit -a -m "Bugfix Commit"
# git checkout master
# git merge --no-ff hotfix1

6. Development on feature1 continues: 
# git checkout feature1

Now my question: Say I need the hotfix in my feature branch, maybe because the bug also occurs there. How can I achieve this without duplicating the commits into my feature branch? I want to prevent to get two new commits on my feature branch which have no relation to the feature implementation. This especially seems important for me if I use Pull Requests: All these commits will also be included in the Pull Request and have to be reviewed although this has already been done (as the hotfix is already in the master). 

I can not do a git merge master --ff-only: "fatal: Not possible to fast-forward, aborting.", but I am not sure if this helped me. 

How-To 
You should be able to rebase your branch on master
# git checkout feature1
# git rebase master

Manage all conflicts that arise. When you get to the commits with the bugfixes (already in master), git will say that there were no changes and that maybe they were already applied. You then continue the rebase (while skipping the commits already in master) with: 
# git rebase --skip

If you perform a git log on your feature branch, you'll see the bugfix commit appear only once, and in the master portion.

[ Git 常見問題 ] How do I force git pull to overwrite everything on every pull?

Source From Here 
Question 
I have a CENTRAL bare repository that has three developer repositories pulling and pushing to it normally. I also have two other repositories that pull from the CENTRAL bare repo: one is the live server, and the other is a test/stage server—each pulling from its own respective branch. The scenario is this: I have a post-update hook script on the CENTRAL repo that automatically accesses the test and live repos and runs a pull command on each. This updates both test and live servers, all depending on what branch has new commits. This all works great. 

The problem is this: there may be times in an emergency that files may be directly updated on the server (via ftp or whateverand the CENTRAL post-update script will then fail since merge/overwrite conflicts will occur.There is no way to avoid this scenario, and it is inevitable. What I would like to have happen is this: I want the pull from the live and test sites to always overwrite/merge on pull. Always. These repos will be pull-only as they are not for development. 

In all my research, I cannot find a good solution to have a pull always force an overwrite of the local files. Is this at all possible? It would make for a great development scenario if so. 

How-To 
Really the ideal way to do this is to not use pull at all, but instead fetch and reset
# git fetch origin master // Fetch branch master from remote

// --hard: Resets the index and working tree. Any changes to tracked files in the working tree since are discarded.
// FETCH_HEAD is a short-lived ref, to keep track of what has just been fetched from the remote repository.
# git reset --hard FETCH_HEAD

// -d: Remove untracked directories in addition to untracked files.
// -f, --force: Git will refuse to delete directories with .git sub directory or file unless a second -f is given.

# git clean -df

(Altering master to whatever branch you want to be following.

pull is designed around merging changes together in some way, whereas reset is designed around simply making your local copy match a specific commit. 

You may want to consider slightly different options to clean depending on your system's needs. 

Supplement 
FAQ- What does FETCH_HEAD in Git mean? 

2017年8月29日 星期二

[ Git 常見問題 ] Force “git push” to overwrite remote files

Source From Here 
Question 
I want to push my local files, and have them on a remote repo, without having to deal with merge conflicts. I just want my local version to have priority over the remote one. 

How-To 
You should be able to force your local revision to the remote repo by using 
# git push -f <remote> <branch>

(e.g. git push -f origin master). Leaving off and will force push all local branches that have set --set-upstream. 

Just be warned, if other people are sharing this repository their revision history will conflict with the new one. And if they have any local commits after the point of change they will become invalid. 

Update: Thought I would add a side-note. If you are creating changes that others will review, then it's not uncommon to create a branch with those changes and rebase periodically to keep them up-to-date with the main development branch. Just let other developers know this will happen periodically so they'll know what to expect. 

Update 2: Because of the increasing number of viewers I'd like to add some additional information on what to do when your upstream does experience a force push. Say I've cloned your repo and have added a few commits like so: 
  1.             D----E  topic  
  2.            /  
  3. A----B----C         development  
But later the development branch is hit with a rebase, which will cause me to receive an error like so when I run git pull: 
Unpacking objects: 100% (3/3), done. 
From  
* branch development -> FETCH_HEAD 
Auto-merging  
CONFLICT (content): Merge conflict in  
Automatic merge failed; fix conflicts and then commit the result.

Here I could fix the conflicts and commit, but that would leave me with a really ugly commit history: 
  1.        C----D----E----F    topic  
  2.       /              /  
  3. A----B--------------C'  development  
It might look enticing to use git pull --force but be careful because that'll leave you with stranded commits: 
  1. D----E   topic  
  2.   
  3.          development  
So probably the best option is to do a git pull --rebase. This will require me to resolve any conflicts like before, but for each step instead of committing I'll use git rebase --continue. In the end the commit history will look much better: 
  1.             D'---E'  topic  
  2.            /  
  3. A----B----C'         development  
Update 3: You can also use the --force-with-lease option as a "safer" force push, as mentioned by Cupcake in his answer: 
Force pushing with a "lease" allows the force push to fail if there are new commits on the remote that you didn't expect (technically, if you haven't fetched them into your remote-tracking branch yet), which is useful if you don't want to accidentally overwrite someone else's commits that you didn't even know about yet, and you just want to overwrite your own: 
# git push <remote> <branch> --force-with-lease 
You can learn more details about how to use --force-with-lease by reading any of the following: 
* git push documentation 
* Git: How to ignore fast forward and revert origin [branch] to earlier commit?


[ Git 常見問題 ] git merge without auto commit

Source From Here 
Question 
Is it possible to do a "git merge", but without a commit? "man git merge" says this: 
With --no-commit perform the merge but pretend the merge failed and do not autocommit, 
to give the user a chance to inspect and further tweak the merge result before 
committing.

But when I try to use git merge with the --no-commit it still auto-commits. Here's what I did: 
#/b] git checkout master 
Switched to branch 'master' 

[b]#
 git branch 
* master 
v1.0
 

# git merge --no-commit v1.0 
Updating c0c9fd2..18fa02c 
Fast-forward 
file1 | 1 + 
1 files changed, 1 insertions(+), 0 deletions(-)
 

# git status 
# On branch master 
# Your branch is ahead of 'origin/master' by 1 commit. 
# 
nothing to commit (working directory clean)

A subsequent "git log" reveals all the commits from the v1.0 branch merged into master. 

How-To 
Note the output while doing the merge - it is saying Fast Forward! In such situations, you want to do: 
# git merge v1.0 --no-commit --no-ff


2017年8月28日 星期一

[ Git 常見問題 ] How to use git merge --squash?

Source From Here 
Question 
I have setup where we have a remote Git server, Here is the scenario which I want to perform, 
* For each bug/feature I create a different Git branch,
* I keep on committing my code in that Git branch with un-official Git messages
* In top repository we have to do one commit for one bug with official Git message,

so how can I merge my branch to remote branch so that they get just one commit for all my check-ins (I even want to provide commit message for this)? 

How-To 
Say your bug fix branch is called bugfix and you want to merge it into master
# git checkout master
# git merge --squash bugfix
# git commit

This will take all the commits from the bugfix branch, squash them into 1 commit and then merge it with your master branch.

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...