====== Version Control Systems ====== * [[http://lib.custis.ru/DVCS_YAC|Сравнение DVCS – несколько задач]] * [[http://stevelosh.com/blog/2010/01/the-real-difference-between-mercurial-and-git/|The Real Difference Between Mercurial and Git]] * [[http://www.rockstarprogrammer.org/post/2008/apr/06/differences-between-mercurial-and-git/|The Differences Between Mercurial and Git]] * [[stackoverflowa>2486662/267197|Merging in Git-vs-SVN]] gives the example, where SVN fails ===== SVN ===== ==== Questions answered ==== === How to recover from ''svn: E175002: Error setting property 'ignore': Could not execute PROPPATCH.'' error? === When committing I get the following error message: svn: E175008: Commit failed (details follow): svn: E175008: At least one property change failed; repository is unchanged svn: E175002: Error setting property 'ignore': Could not execute PROPPATCH. This happens because client application has used "CRLF" end-of-line marker for ''svn:ignore'' property value (see [[http://tigris-scm.10930.n7.nabble.com/Failed-to-execute-WebDAV-PROPPATCH-when-trying-to-commit-a-quot-ignore-quot-file-td71211.html|Failed to execute WebDAV PROPPATCH when trying to commit a "ignore" file]] and [[eclipsetracker>395063|JavaHL connector fails to commit svn:ignore property]]). To fix this re-save this property in Unix format. For that: - Run ''svn propedit svn:ignore trunk''. This will start external ''EDITOR'' (''vi'' in my case). - Now in ''vi'' type '':e ++ff=unix''((Check [[http://vim.wikia.com/wiki/File_format|here]] for more information about this option)) and then '':w!'' to save the content Repeat this for all "damaged" properties. After that commit succeeds. === [[stackoverflow>1230700|How to ignore files recursively?]] === Since v1.8: ''%%svn propset svn:global-ignores "*.o"%%'' ===== Mercurial ===== ==== Questions answered ==== === What should I do if I got "hg abort: changelog. no node!" === Perhaps, you also got a complain $ hg status $ abort: working directory has unknown parent 'd44a65b441c2'! In this case do: $ hg debugsetparents default $ hg revert --no-backup --all -r tip ===== Git ===== * [[eclipse>EGit/User_Guide|Git for Eclipse User Guide]] * [[habrahabr>209400|Использование mcdiff в качестве внешней DIFF-утилиты]] * [[habrahabr>137615|Проблемы с производительностью Git на большом репозитории]] * [[youtube>006RUPVIP-c|Managing huge files on the right storage with Git LFS]] explains also a bit the Git object tree, hooks and filters. * [[https://github.com/k88hudson/git-flight-rules|Flight rules for Git]] * [[habrahabr>267595|19 советов по повседневной работе с Git]] * [[https://git.wiki.kernel.org/index.php/GitFaq|Git FAQ]] * [[http://sethrobertson.github.io/GitFixUm/fixup.html|Undoing, fixing, or removing commits in git]] * [[http://git.or.cz/course/svn.html|Git – SVN Crash Course]] ==== Additional options ==== === ''%%git config --global branch.autosetuprebase always%%'' === From [[stackoverflowa>22147540/267197|autosetuprebase vs autosetupmerge]]:
Controls whether new branches should be set up to be rebased upon ''git pull'', i.e. your setting of ''always'' will result in branches being set up such that git pull always performs a rebase, not a merge. Be aware that existing branches retain their configuration when you change this option.
=== ''%%git config --global pull.rebase preserve%%'' === From [[stackoverflowa>18756102/267197|Make git pull --rebase preserve merge commits]]:
If a user is working on master, and has merged in their feature branch, but now has to ''git pull'' because master moved, with ''pull.rebase'' their feature branch will be flattened into master. This is because ''git pull'' currently does not know about rebase's preserve merges flag, which would avoid this behaviour, as it would instead replay just the merge commit of the feature branch onto the new master, and not replay each individual commit in the feature branch. Add a ''%%--rebase=preserve%%'' option, which will pass along ''%%--preserve-merges%%'' to ''git rebase''.
==== Questions answered ==== === What Git clients are available for Windows? === * [[https://git-scm.com/download/win|Official Git for Windows]] compiled from [[github>git-for-windows/git|Git for Windows]]. * [[https://gitforwindows.org/|Git for Windows]] === [[stackoverflowa>26785200/267197|Revision selection (''HEAD~'' vs ''HEAD^'' vs ''HEAD@{}'')]] === * ''HEAD~2'' -- 2 commits older than ''HEAD'' * ''HEAD^2'' -- the second parent of ''HEAD'' if ''HEAD'' was a merge, otherwise illegal * ''HEAD@{2}'' -- refers to the 3rd listing in the overview of ''git reflog'' See also [[stackoverflowa>2222920/267197|What's the difference between HEAD^ and HEAD~ in Git]]. === How to undo last commit? === From [[stackoverflowa>6866485/267197|Git undo last commit]]: * ''%%git reset --hard HEAD^%%'' \\ Will revert all current changes and revert to previous commit. The commit on the top is destroyed. * ''git reset HEAD^'' \\ Will keep all current changes and switch to previous commit. The commit on the top is kept. * ''%%git reset --hard%%'' \\ Will revert all current changes. * Or make changes on top (''git rm'', ''git add'', ...) and add them to previous commit with: \\ ''%%git commit --amend%%'' * To revert changes for some file or directory use: \\ ''git checkout '' * To undo commit ''f25fcf53'' by follow-up rollback commit: \\ ''git revert f25fcf53'' === How can I squash my last N commits together? === From [[stackoverflowa>5190323/267197|How can I squash my last X commits together using git?]]: Suppose you're on master and you want to squash the last 12 commits into one: - ''%%git reset --hard HEAD~12%%'' - ''%%git merge --squash HEAD@{1}%%'' (needs additional quoting on Windows e.g. ''%%git merge --squash "HEAD@{1}"%%'') - ''git commit'' The same: - ''%%git reset --soft HEAD~12%%'' - ''git commit'' To apply changes to remote repository, do: * ''%%git push --force origin master%%'' (replace ''master'' with the name of your current branch). \\ [[http://stackoverflow.com/a/27571408/267197|With eclipse]]: //Team -> Push Branch...// and check //Force overwrite of branch on remote if it exists and has diverged//. === How to remove a commit? === Suppose ''ec5ef1e9'' is commit hash you want to remove, then below will do the job: ''%%git rebase -p --onto ec5ef1e9^ ec5ef1e9%%'' === How to change the author or message of Git commit? === From [[stackoverflowa>3042512/267197|Change commit author at one specific commit]]: For example, if your commit history is ''A-B-C-D-E-F'' with ''F'' as ''HEAD'', and you want to change the author of ''C'' and ''D'' then you would: - ''git rebase -i B'' \\ Change the lines for both ''C'' and ''D'' to ''edit''. \\ Once the rebase started, it would first pause at ''C''. - ''%%git commit --amend --author="Author Name "%%'' - ''%%git rebase --continue%%'' \\ It would pause again at ''D''. - ''%%git commit --amend --author="Author Name "%%'' again - ''%%git rebase --continue%%'' \\ This would complete the rebase. To [[stackoverflowa>179147/267197|change the message]]: * ''%%git commit --amend%%'' (will launch ''vim'' to enter new message) or ''%%git commit --amend -m "New commit message"%%'' \\ Will amend the top of the current branch. The same technique can be used to [[stackoverflowa>16762949/267197|insert commit into the history]] as alternative to [[https://printf2linux.wordpress.com/2012/04/09/insert-a-commit-in-the-past-git/|this one]]: - Commit to the changes to the HEAD and ''git rebase -i B'' where ''B'' is some commit in the past after which you want to insert the given one. - In the editor, reshuffle lines in order which is needed. After save+exit rebase will continue and reorder commits. === [[stackoverflowa>26359665/267197|How to exclude a particular file from commit?]] === - Update the version of file in index to one in ''HEAD'' minus one commit thus effectively undoing the change: \\ ''git reset HEAD~ '' - Replace the content of the file in working tree (from history or from stash) and then do: \\ ''git add -u '' - After that do ''%%git commit --amend%%'' or ''%%git rebase --continue%%''. :OPT: Alternative solution is to rewrite the whole history with the given file removed: ''%%git filter-branch --prune-empty --tree-filter 'rm -f file_to_remove' --tag-name-filter cat -- --all%%'' === [[superuser>293941|How to rewrite git history and replace EOL from CRLF to LF?]] === - ''%%git filter-branch --force --prune-empty --tree-filter 'git ls-files | xargs file | sed -n -e "s/\(.*\): .*text.*/\1/p" | xargs dos2unix' --tag-name-filter cat -- --all%%'' - ''%%git push --force --all%%'' - ''%%git push --force --tags%%'' - Set ''core.autocrlf = input'', see [[stackoverflow>3206843|How line ending conversions work with git core.autocrlf between different operating systems]]. === [[stackoverflowa>31859803/267197|How to split directories into separate git repository preserving commit history?]] === For one directory ''mydir'' in repository ''myrepo'' one can do the following: - Clone repo (for safety): \\ ''git clone myrepo mynewrepo'' - ''cd mynewrepo'' - Filter out commits which are not relevant to ''mydir'': \\ ''%%git filter-branch --prune-empty --subdirectory-filter mydir --tag-name-filter cat -- --all%%'' \\ :OPT: ''%%git filter-branch --prune-empty --subdirectory-filter mydir HEAD%%'' Above method has one disadvantage which is written in [[https://git-scm.com/docs/git-filter-branch#git-filter-branch---subdirectory-filterltdirectorygt|documentation]]:
The result will contain that directory (and only that) as its project root.
To move the directory one level deeper requires another history rewrite... hence it's better to take another approach: - Clone repo: \\ ''git clone my-repo my-repo-copy'' - ''cd my-repo-copy'' * Remove all except ''mydir1'', ''mydir2'', ...: \\ ''%%git filter-branch --tree-filter 'ls -1 | egrep -v "^(mydir1|mydir2)" | xargs rm -rf .gitattributes .gitignore' 2> /dev/null" HEAD%%'' \\ ''cd ..'' * :OPT: ... or move ''mydir1'', ''mydir2'', ... to a temporary directory and split : \\ ''%%git filter-branch --tree-filter "mkdir tmpdir; mv mydir1 mydir2 tmpdir 2> /dev/null" HEAD%%'' \\ ''git subtree split -P tmpdir -b tmpbranch'' \\ ''cd ..'' - Create new repo: \\ ''mkdir new-repo && cd new-repo && git init'' - Pull changes from branch: \\ ''git pull ../my-repo-copy tmpbranch'' - :OPT: Additionally one can add more commits from another repository: * ''%%git fetch ../another-repo --no-tags +tmpbranch:tmpbranch%%'' * ''git rebase tmpbranch'' - Finally push to origin: \\ ''%%git remote add origin git@github.com:my-user/new-repo.git && git push origin -u master%%''
=== How to push all commits but the last one to origin? === - ''git checkout HEAD~'' - ''git push origin HEAD:master'' - ''git checkout master'' === How to see all outgoing commits? === ''git cherry -v'' to list all outgoing commits (to be pushed) for current branch. === How to fetch changes from upstream? === From [[stackoverflowa>4169905/267197|Update my github repo which is forked out from another project]]: - ''%%git remote add upstream https://github.com/project/project.git%%'' to add new upstream URL - :OPT: And either: * ''git pull upstream [branch to merge]'' which is the same as ''git fetch upstream'' + ''git merge'' (for example: ''git pull upstream master'', ''git pull upstream release_2016-01-20'') * or ''git fetch upstream'' + ''git rebase'' to rebase your work without needing a merge See [[http://git-scm.com/book/en/Git-Branching-Rebasing|here]] about how merge differs from rebase. === How to work with branches? === * ''git branch'' show all local branches (current branch is marked) * ''git branch '' to create new branch and start working in it * ''git checkout '' to change the branch, e.g. ''git checkout master'' will switch the repository to main branch * ''git branch -m '' to rename local branch * ''git branch -D '' to delete the branch * ''git branch -f master HEAD'' to switch master branch, e.g. ''git branch -f master 010203A'' to switch to particular commit (see [[stackoverflowa>26570472|How to move master to HEAD]]) === How to create a branch to implement new feature if ''origin/master'' branch already contains some features different from ''upstream/master''? === To create a new branch for feature "myfix": - ''git checkout -b myfix'' - Make fixes or implement a feature... - ''git fetch upstream'' - Rebase current branch on the top of ''upstream/master'' with differences from ''master..myfix'' incorporated: \\ ''%%git rebase --onto upstream/master master%%'' - ''git push origin myfix'' - Submit pull request... If you need to refine after submitting a pull request: - Do some local master changes - ''git checkout myfix'' - Replay these changes on branch: \\ ''git rebase master'' - Make fixes; probably do \\ ''%%git commit --amend%%'' - Replay on the top of ''upstream/master'': \\ ''%%git rebase --onto upstream/master master%%'' - ''git push origin myfix -f'' If any conflicts during the rebase, use ''%%git checkout --theirs %%'' to replace the file with your version (during rebase ''%%--ours%%'' is referring ''upstream/master''). === How to remove a remote branch? === From [[stackoverflowa>2003515/267197|How do I delete a Git branch both locally and in Github]]: Use ''%%git push origin --delete branch%%'' which is the same as ''git push origin :branch''. === How to rename a remote branch? === From [[stackoverflowa>4754132/267197|git: renaming branches remotely]] and [[stackoverflowa>7086922/267197|Renaming remote git branch]]: * ''git branch new-branch-name origin/old-branch-name'' * ''git push origin new-branch-name'' will add new branch * ''git push origin :old-branch-name'' will remove old branch or * ''git push origin :old-branch-name'' will remove remote old branch * ''git push origin local-branch-name:new-branch-name'' will push local branch to remote but with new name === How to rename a remote tag? === * ''git tag new_tag old_tag'' will create a new tag pointing to same commit as old tag * ''%%git push --tags%%'' will push new tag to remote * ''git push origin :refs/tags/old_tag'' will delete the old tag from remote === How to compare? === A file with another branch: * ''git diff '', e.g. ''git diff upstream/master pom.xml'' Two tags: * Combined diff: \\ ''%%git diff --color -M tags/one tags/two%%'' * With log message for each commit: \\ ''%%git log --color --full-diff -p -M tags/one..tags/two%%'' === [[stackoverflowa>7203551/267197|How to log history for removed file?]] === ''%%git log --full-history -- /path/to/removed/file%%'' === [[stackoverflowa>4262780/267197|How to list all commits by given user?]] === ''%%git log --author="Jon Smith"%%'' === How to find the commit where the bug was introduced? === ''git bisect'' -- это средство для двоичного поиска коммита, который все сломал. Допустим вы знаете коммиты где бага не было, и где баг уже есть. Цель -- найти коммит, который посадил этот баг, за минимальное количество шагов. Откатываемся к коммиту, который точно посередине. Если бага в этой точки нет, то проблемный коммит справа, иначе он слева. Повторяем пока не найдём. Особенность ''git bisect''-а, что он умеет правильно обрабатывать нелинейные куски истории. === [[stackoverflow>5098256|Git blame: how to go back in commit history?]] === After you have listed the latest commit reported by ''git blame'' (assuming that is ''f25fcf53''), do the following iteratively until you find the needed commit (perhaps you need to make line number adjustment on each iteration): ''git blame -n -L 810,+40 f25fcf53^ file.php'' === [[stackoverflow>17563726|How to display a given commit as a diff?]] === * ''git show f25fcf53'' * ''git diff f25fcf53^!'' === [[stackoverflowa>6658352/267197|How to format a given commit as a patch?]] === ''%%git format-patch --stdout - %%'' For example ''%%git format-patch -1 f25fcf53%%'' will create a patch for one particular commit giving it a name derived from comment message. This patch can later be applied via ''git am '' === How to configure password for remote repository? === * In ''.git/config'' change URL to ''https://user:password@github.com/...git''. * Use [[https://help.github.com/articles/caching-your-github-password-in-git/|password caching]] (check also [[stackoverflowa>5343146/267197|Is there a way to skip password?]]): \\ ''git config credential.helper store'' === [[stackoverflowa>50496599/267197|When and how does git use deltas for storage?]] === - When optimizing the local storage. Git by default regularly runs ''[[https://git-scm.com/docs/git-gc#git-gc---auto|git gc --auto]]'' to optimize the storage, which in turn runs ''git repack'' when necessary. - When sending the bulk of changes to the client on ''git fetch''. In this case a [[stackoverflowa>52452772/267197|thin pack is created]]. === [[stackoverflow>2116778|How to reduce repository size?]] === :WARN: Use below instructions with care. Think twice about what you really need to be kept. - [[stackoverflowa>41893536/267197|Delete all tags]]: \\ ''%%git tag -d $(git tag)%%'' - [[stackoverflowa>52006270/267197|Delete all local branches]] except ''master'': \\ ''%%git branch -D $(git branch | grep -v "master")%%'' - [[stackoverflowa>37565829/267197|Delete all remote branches]] except ''master'': \\ ''%%git branch -r -D $(git branch -r | grep -v "master")%%'' - Remove reflog entries not reachable from the current tip: \\ ''%%git reflog expire --all --expire=all%%'' - Run one of (more or less equivalent): * ''%%git repack -a -d -f --depth=500 --window=500 --threads=2%%'' * ''%%git gc --prune=now --aggressive%%'' === How to integrate Cygwin Git into Visual Studio code? === Based on solution ''[[github>nukata/cyg-git/blob/master/git.c|git.c]]'': * Compile the following C program (change path to wrapper script accordingly) ''gcc git-wrapper -o git-wrapper.exe'': #include #include #include int main(int argc, char **argv) { char buf[4000] = "/bin/bash -c 'C:/Applications/CygWin/git-wrapper.sh"; int rest = sizeof(buf) - strlen(buf) - 2; /* 2 for "'\0" */ for (int i = 1; i < argc; i++) { rest -= strlen(argv[i]) + 3; /* 3 for " \"\"" */ if (rest < 0) { fprintf(stderr, "arguments too long\n"); return 1; } strcat(buf, " \""); strcat(buf, argv[i]); strcat(buf, "\""); } strcat(buf, "'"); return system(buf); } * Created wrapper script: #!/bin/bash wrap_output="" argv=("$@") for ((i = 0; i < $#; i++)) do arg="${argv[$i]}" if [ $i = 0 -a "$arg" = 'rev-parse' ] then wrap_output=yes elif [[ -n "$arg" && "$arg" != -* ]] then argv[i]=`cygpath -u "$arg"` fi done if [ $wrap_output ] then if out=`git "${argv[@]}"` then if [ -n "$out" ] then if [[ $out = -* ]] then echo "$out" else cygpath -w "$out" fi fi else x=$? echo "$out" exit $x fi else exec git "${argv[@]}" fi * Configure VS Code to use it: add ''%%"git.path": "C:\\Applications\\CygWin\\git-wrapper.exe"%%'' to ''%APPDATA%\Code\User\settings.json''. See also: * [[github>microsoft/vscode/issues/7998|Support cygwin git]] * [[https://gist.github.com/nickbudi/4b489f50086db805ea0f3864aa93a9f8|Cygwin Git + VS Code compatibility]] === Error ''The requested URL returned error: 403 while accessing...'' === From [[stackoverflowa>6562940/267197|Can't clone any repository in Git]]: Update git to v1.7.x.