I'm running into an issue where branch merging fails because Crashlytics binaries are changing. I added Crashlytics to the gitignore, but now the framework doesn't show up if I checkout branches anymore.
Is there a way to deal with the merge conflicts or a way to tell git to ignore changes to the file, but keep the file itself?
If you want the file in a fresh clone, or after cleaning a git repository it needs to be tracked by git.
Binary files are not pretty to merge. From you question it sounds like there isn't anything to merge, but the decision is just which file to keep.
One thing you could do is define custom automatic merge behavior for these binaries via .gitattributes and .git/config settings:
Add the following to your .gitattributes (or create a new file with that content in the root of your git repository)
path/to/file merge=nomerge
and place the following into a git configuration file (.git/config, or ~/.gitconfig)
[merge "nomerge"]
name = keep current version
driver = true
This instructs git just ignore the conflict and keep the file from the branch into which you are merging.
The driver = true specifies an external program to use for merging. In this case the program is true which should be available on any unix like system and does nothing successfully.
See the gitattributes manpage section on Defining a custom merge driver on ways to add real custom logic if you need something smarter.
On could do really complex things like always keeping the higher version of the file, if there is any version indicator in file for example.
You should git add the .gitattributes file to the repository. The actual merge driver definition can't be stored in a way that new clones get it automatically out ouf the box. So you need to add this manually into each clone or in the per user config on every computer where you need it.
Related
I am using Windows and Git and I had modified a file. No matter how many times I did a git add and commit, the file kept showing up as modified and i could not for example do a git pull --rebase. I assume I did something wrong and screwed up the local Git repo so I decided to clone the repo from github, into a completely new directory. To my surprise, even in this new directory tree when I do a git status the same file shows up as modified -- it is as if it is somehow modified in the github (remote) repo which does not make sense to me. Moreover, the version of the file in cloned local repo does not have the latest version of the code that i can see when i look at the code on github. How can i fix this? I am concerned that someone else cloning the code will end up with the same problem. (Apparently only I am seeing this problem -- I did not somehow manage to corrupt the github repo which leads me to believe this is a git/windows issue.) As far as what I think I did wrong is when I modified a file and did a git add, i misspelled the directory path by using a lower case letter instead of an uppercase and then adding one file resulted in the other, properly spelled path showing up as modified and vice versa. I don't know if a symlink on windows got created -- the file contents are identical. But one would think cloning (via Eclipse) into a completely new directory tree would make this a non-issue.
I looked through replies but it seems like the basic problem is Window's case insensitivity and this caused some (to me) weird behavior. In particular, I simply could not delete one of the folders -- they were "entangled." So the simple solution was to delete the folder and its contents from unix which is case sensitive. Then I checked out a fresh repo and problems appear to be completely resolved.
You mentioned in a comment that you discovered one commit containing two problematic files: one named Login/Login.tsx and one named login/Login.tsx. This comment is on a related question; see my answer there for a discussion of Git's method of naming files in its index, vs what your OS requires in your working tree.
Your solution—use a Unix or Linux machine, where you get a case-sensitive file system, to repair the situation—is probably the easiest and best way to deal with this. If you can establish a case-sensitive file system on your own machine, that also allows easy dealing with this (see my answer to another related question for a macOS-specific way to make a case-sensitive file system).
Given that what you wanted was simply to delete one of the spellings, though, git rm should allow you do that. In particular git rm --cached login/Login.tsx would drop login/Login.tsx from Git's index, without affecting Login/Login.tsx. This could leave your working tree with an existing login folder, though.
It's important—at all times, really, but especially when working within a situation like this—to realize that Git itself doesn't actually need or use your working tree to make new commits. Each commit contains a full snapshot of every file that Git knows about. These files exist as "copies" in Git's index.1 Hence there are actually three copies of each file:
A frozen version of each file appears in the current commit (whatever that commit's hash ID is).
A "copy" (see footnote 1) of that version appears in Git's index. You can replace this copy with different content, and the read-only copy in the commit doesn't change. You can remove this copy entirely, and the read-only copy still doesn't change. Nothing in any existing commit can or will ever change. The index copy exists precisely so that you can replace it, or remove it, or whatever. In effect, the index—or staging area, if you prefer this term—acts as your proposed next commit. It's merely filled in from a commit.
Finally, there's a regular, ordinary, everyday file. This copy goes into your working tree or work-tree. To put this copy in place, Git must use your OS's file-manipulation facilities. That may require creating folders and files within the folders. If those are case-insensitive, and Git goes to create a Login folder when a login folder exists, or vice versa, the OS will say: nope, sorry, already exists. Git will do its best to accommodate the OS by using the "wrong" case anyway, and will create a file within that wrong-case folder—or perhaps destroy some other work-tree file that has the same name except for case, or whatever.
This last bit, where your work-tree files end up with the wrong names and/or in the wrong folders and/or end up overwriting similar files whose name differs in case somewhere, is a problem for you. It's not a problem for Git, though. Git just keeps using the index copies of each file. The next git commit you run uses whatever is in Git's index. The fact that your work-tree doesn't match is not a problem for Git. It's just a problem for you, because the normal everyday git add command means make the Git index entry for this file match the copy that's in my work-tree, and if that's the wrong copy, well, that's a problem.
In any case, once you have a correct commit in Git as your current commit, and extracted into Git's index, you can do whatever you like to your work-tree, including remove large swaths of it, or rename folders, or whatever. Get it set up however you like, then use git checkout or git restore to re-extract all or part of the current commit to your work-tree. Now that you've eliminated the name-case-issues in Git's commit and index, and cleaned up or removed any problematic files and/or folders in your work-tree, Git can create correct-case folders and/or files as needed. It's the process of getting the correct commit into Git that's painful, except on a case-sensitive file system.
1"Copies" is in quotes here because the files in Git's index—which Git also calls the staging area—are in a special Git-only format that de-duplicates content. When the copies that are in Git's index match the copies that are in some existing commit, Git is really just re-using the existing commit's files. Files with all-new content actually require a new internal blob object, which Git creates as needed; after that, the content will be de-duplicated as usual.
I'm new to git and have a git repository that I use with GitKraken.
In this repository I have multiple branches, and can move from branch to branch in order make modifications where necessary.
I am now in a situation where I'll be making some large modifications to 1 branch that I do not want to commit but in the meantime I would like to make some minor modifications to another branch.
I'm used to work with TFS and there I can just checkout branch to another folder.
I've tried to just copy the folder and my first impression is that this should work....
But, I have seen online remarks that say that I should clone a repository instead.
The git version is lower then 2.5 so I can't use Git-worktree.
Is it ok to just copy the folder or can this have an unexpected effect?
Yes, if you copy the whole folder from the root of the checkout, including the hidden .git folder, then you can make changes to each working copy independently. Each contains their own copy of the repository objects and they will behave exactly as if you have run two separate clones.
As discussed in the comments this isn't necessarily a good use case for this, though: it would be easier (and more disk-space-efficient) to commit your large changes to a local branch so that you can then switch and make other changes. There's no real downside to this; if you do want to remove that temporary commit later then that's easily done as well.
However if you are going to do this, then you probably want to
run a git repack -ad first, so that there are fewer files in the objects tree to copy
consider using git clone --reference instead, which might be slightly more disk-space-efficient
or you want a clean working copy you can create a new working copy folder, copy only the hidden .git folder into the new working copy and then git reset --hard to check out all of the files there too.
You may want to see if git stashing will work for you. I don't recommend copying to a new folder. Mostly because I don't know if it's even possible and I've never seen that as a recommendation. Cloning should also work but it sounds like you are interested in shelving/stashing vs. committing your changes in branch1 before checking out branch2.
https://git-scm.com/book/en/v1/Git-Tools-Stashing
I am working on a Swift based XCode project that is synced with Git based master repository. One of my team member has added few files, to the master which I have pulled.
I find those files in my project directory, but not in my project. When I am manually trying to add these files to the project, in that case, I am getting Modify tag on my project, then I am unable to pull new changes from master.
This is very annoying. How do I take care of this.
Also, how do we make sure as a team that everyone of us is working separately on different module, and make surely everyone is able to commit/pull each other's changes.
The project folder with M tag is prohibiting us from doing so.
Edit 1
I have followed steps for this as well
git rm -r --cached ProjectName.xcodeproj
git commit -m "Removed file that shouldn't be tracked"
Even after doing this,
I had made changes in File1.swift, with my team member's changes in File2.swift
He had already committed it, I wanted to pull those changes, however due to changes in File1.swift I was unable to pull it.In order to make it work, I had to discard changes in File1.swift and then only I was able to pull those changes. If this is so, then it is defeating the purpose of using git
Xcode project files
The Xcode project file, or to be more precise, the pbxproj file inside the xcodeproj container keeps track of all files (among other things). Unlike Eclipse, Xcode does not monitor your source/project folder for changes thus does not update the list of files which can lead to inconsistencies after a merge.
Merge conflicts
If your team member adds or removes a file in his local copy of the repository and pushes his changes to the server, he basically overwrittes the pbxproj and therefore updates the list of files of the Xcode project. If you pull those changes there are two possible scenarios:
Git can merge the changes automatically which usually means it will keep your copy of the pbxproj file without the updated file references.
Git cannot merge the changes and therefore indicates a merge conflict that you need to resolve yourself. Depending on the differences and amount of changes these merge conflicts can be pretty annoying to resolve. Sometimes it might be easier to just delete your copy of the pbxproj file, use the one from the server and reapply your local changes, e.g., add file references.
In both cases you might need to compare your pbxproj file against the one from the server and merge things by hand. And yes, your project file will be marked with an M (for modified) which is perfectly fine. Just commit your changes and you are good to go again.
One more thing: Whenever you want to pull changes from the git server you can either stash your changes (git stash) or commit them.
Avoiding merge conflicts
In case you want to avoid merge conflicts in the future, I recommend having a look at the following tools.
Cocoapods
Cocoapods can be used to modularise your project into smaller pieces by creating private Pods. The benefit of this technique: You do not have to keep track of newly added or removed files. Just run pod update and you are up and running again. There are several blog posts that describe this technique in detail, e.g., here
phoenx
At my former company we had a pretty huge codebase and ran into some trouble when using Cocoapods. Therefore, we have developed our own meta-build system called phoenx. Phoenx can generate Xcode project and workspace setups of arbitrary complexity. It uses metadata files (something like Podfiles and Podspecs) to generate the projects etc. . Build settings will be stored in xcconfig files. At the moment it does not provide any setup tool so you have to invest a bit of time to write the xcconfig and metadata files by hand. We are working on a more convenient way to use it though. If you want to give it a try you can install it via sudo gem install phoenx. Documentation is available on GitHub.
Hope that helps!
We work with a git respository that has over 20,000 files.
My group maintains local versions of about 100 or so of configuration and source files from this repository. THe original acts as a sort of base that several groups modify and tweak to their own needs (some core things are not allowed to be changed, but front end and some custom DB stuff are different between groups)
So we want to update to the latest version generally, but not have the git update overwrite the files that we keep local modifications for.
The machines we use are windows based. Currently the repository gets cloned to a windows server that then gets checked out/cloned to the development machines (which are also windows). The developers make changes as necessary and recommit to our local repo. The local repo updates against the master daily. We never commit back to the master.
So we want all the files that haven't been changed by our group to update, but any that have been changed (ever) won't get updated.
Is there a way to allow this to happen automatically, so the windows server just automatically updates daily, ignoring those files we keep modifications for. And if we want to add a new file to this "don't update" list its just a right-click (or even a flat file list away). I looked at git-ignore but it seems to be for committing, not for updating.
Even better would be a way to automatically download the vanilla files but have them renamed automatically. For example settings.conf is a file we want to keep changes on generally, but if they modify the way entries in that file are handled or add extra options it would be nice it it downloaded it as settings.conf.vanilla or something so we just run a diff on .vanilla files against ours and see what we want to keep. Though this feature is not absolutely necessary and seems unlikely.
If this cannot be accomplished on a windows machine (the software for windows doesn't support such features), please list some Linux options as well if available. We do have an option to use a Linux server for hosting the local git repo if needed.
Thanks.
It sounds like you're working with a third party code base that's under active development and you have your own customisations which you need to apply.
I think the answer you're looking for is rebase. You shouldn't need to write any external logic to achieve this, except for a job which regularly pulls in the third party changes and rebases your modifications on top of them.
This should also be more correct than simply ignoring the files you've modified, as you won't then accidentally ignore changes that the third party has made to those files (you may sometimes get a conflict, which could be frustrating, but better than silently missing an important change).
Assuming that your local repo is indeed simply a fork, maintain your changes on your own branch, and every time you update the remote repository, simply rebase your local branch on top of those changes:
git pull origin master
git checkout custom_branch
git rebase master
Edit
After you've done this, you'll end up with all the changes you made on your custom_branch sitting on top of master. You can then continue to make your customisations on your own branch, and development of the third party code can continue independently.
The next time you want to pull in the extra changes, you'll repeat the process:
Make sure you're on the master branch before pulling in changes to the third party code:
git checkout master
Pull in the changes:
git pull origin master
Change to your customised branch:
git checkout custom_branch
Move your changes on top of the third party changes:
git rebase master
This will then put all your own changes on top of master again. master itself won't be changed.
Remember that the structure of your repo just comes from a whole set of "hashes" which form a tree. Your branches are just like "post it" notes which are attached to a particular hash, and can be moved to another hash as your branch grows.
The rebase is like chopping off a branch and re-attaching it somewhere else. In this case, you're saying something like "chop off our changes and re-attach them on top of the main trunk".
If you can install a visual tool like GitX, it will really help to see how the branch tags move around when you rebase. The command line is ideal for working with but I find something like GitX is invaluable for getting a handle on the structure of your repo.
I can create a repo and use GitHub / BitBucket fine for my own projects. I have had problems when collaborating with other developers or trying to fork a project on GitHub.
I am aware of other answers like Best practices for git repositories on open source projects but there are OSX / Xcode specific problems I want to know how to solve.
.DS_Store files can be a pain. You can use .gitignore to prevent, but what happens if they have already been included, or another developer adds them back in through a clumsy git command?
The .xcodeproj will have changes to the directory names and developer profiles for the other person. What's the best way to do merges or to avoid conflicts?
If I have forked or pulled from a github project, how can I clean up these issues and also minimise merge conflicts for the maintainer?
If people have an example .gitignore created for Xcode, or scripts they use to initialise their repos then that would be great!
Put .DS_Store in .gitignore. Then, if you haven't already, add .gitignore to the repo. (You should not ignore .gitignore.) Now all developers will ignore .DS_Store files. If any were added to the repo erroneously before you put .DS_Store in .gitignore, you can now remove them (in a commit) and they should stay out.
The xcodeproj is a directory. The only file in this directory that must be in the repository is the project.pbxproj file. I generally ignore all of the others by putting these lines in my .gitignore:
*.xcuserstate
project.xcworkspace/
xcuserdata/
You should avoid putting absolute paths in your build settings. Use relative paths.
Your Debug and Release builds should use iPhone Developer as the code signing identity, so that Xcode will automatically select the local developer's profile. When you want to create an IPA (for distribution), Xcode will offer to re-sign it with a different identity, at which point you can choose your distribution profile if you need to.
If you're trying to use a project from github that has made these mistakes, you can try to get the maintainer to fix them, or you can make sure you don't touch the .DS_Store files and the code signing identities in the same commits that you want to send upstream.
For the 2nd issue regarding the .xcodeproj and merge conflicts.
Using a .gitattributes file to specify that merge conflicts for all .pbxproj files should be handled using the merge=union strategy, which should mean that Git knows to merge in the changes from both sides of the conflict, taking the upstream changes first.
This article explains it in a bit more depth
I'll try one by one:
I. You need to use git filter-branch only if you need to remove the files from your history completely. If those files do not contain any credit card information, then i think the following should be enough:
git rm --cached .DS_Store
git commit -m "{Your message}"
then add this file to .gitignore and commit it.
This will commit the removal of the file from the repository but will keep the file in working directory. If you push it though and then somebody else will pull this commit, they might have their file removed, so you MUST communicate this.
By committing .gitignore you will prevent other developers from adding this file again.
If you're not a maintainer, then i don't think you should do anything, but address this issue to the maintainer.
II. I'm a strong believer that hidden files of any nature are most of the time not supposed to be put into the repository exactly for that reason. Therefore i think that you should do the same thing with .xcodeproj as with .DS_Store and put it into .gitignore and commit it. .gitignore is the exception for the rule above.
III. If those files are properly ignored , then there will be no issues in future with them. If they are already in the repo and somebody wants do such cleanup it should be done by maintainer and communicated inside the team.
Hope that helps!
git filter-branch might help you to remove unwanted files (.DS_Store files) from your repository -- see e.g. https://help.github.com/articles/remove-sensitive-data
If a clumsy git commit has added files you should be able to replay the corrected changesets onto a clean repository.
You're right in the sense that if a .DS_Store is already added the .gitignore won't be of much help however I think this is still a good resource for you and others.
When I start a project, I normally look at this list to see if there is a good .gitignore already existing. More specifically for you, this one is the Objective-C .gitignore.
Hopefully those resources are of some use.
As a Mac user you should download a tool like SourceTree which supports Git Flow. Git Flow will help you establish some best practices around how your collaborators will commit code to the repo and at the very least make merge conflicts less frequent and more manageable. For a set of gitignore files for various project types you can go to GitHub and download one that is ready to go. For Xcode they have it listed as Objective-C.gitignore. That is a good starting place and it even covers Cocoapods. If you're using external libraries, your project should use CocoaPods so that you can isolate that code and keep it outside of your repo and avoid git submodules.
Now when you find a file has made it into your repo like .DS_Store just remove it, and move on. Make sure you add it to the .gitignore file that is checked into the project.
As for xcodeproj... there shouldn't be that much customization within the file that is user specific since the above mentioned gitignore filters that out. If a scheme is to be shared make sure you check shared under Manage Schemes and you will check in files in that subdirectory. You should be using automatic selection of certificates so the only real choice is Developer or Distribution. You should also take advantage of variables provided within Xcode that avoid hardcoding complete paths. When trying to think of an example Plists came to mind, in this case, you might have written /Users/me/MyProject/Resources/MyProject.plist, but instead should use $(SRCROOT)/resources/MyProject.plist.