How to execute "local commit" in git?

I am using git and I would like to create a commit that does not synchronize with the remote repository. Such a commit should “float” on top of all other commits in the local repository in order to avoid affecting the history. I could use such a commit to store local changes (configuration changes, debug flags, local workarounds, etc.).

I am currently manually reinstalling when I commit myself to reorder the commit at the top, and I click using HEAD^ to avoid pushing local changes. I also considered the possibility of making changes to the wallet, but this is less convenient because it interferes with the normal use of the wallet. Another alternative is to just leave all these local changes unset and use git add -p every time I want to commit. However, with a large number of trivial local changes, this becomes a problem.

Here is an example of my current workflow:

My repository initially looks like

 A---B---C---F master 

where "F" is my floating commit.

I am doing a commit:

 A---B---C---F---D master 

then git rebase -i HEAD~2 to reorder:

 A---B---C---D---F master 

and then git push remote HEAD~1... push everything except the local F commit.

Change F contains changes to existing versions of files and may contain an arbitrary number of changes. (If I can do more than one floating, that would be even better, since I could then separate the local changes).

+42
git
Nov 07 '12 at 19:37
source share
8 answers

How to transfer these changes to a local branch that you regularly update / merge from your main branch? Thus, there would be no danger of climbing them.

+18
Nov 07
source share

So it looks like you want two things:

  • Some commits should be kept confidential (for example, on a local branch) and never push or merge when you pull; they must remain "after" the general commits.

  • It should be mostly transparent to you; you want to work with the wizard, and the local branch is supported automatically. You simply decide which commits should be local, and the commands that interact with the remote repositories will ignore them.

So you want to write a script (name it git-something and put it in your path to add an additional git command) to identify and eliminate these commits. You will need a trigger for the script to recognize local commits. An easy way to do this is to put the magic word in the commit description - one that you will never use in real / shared commit - for recognizing a script. (If this sounds too loud for you, you can also use a special file in the commit tree, for example .THIS_COMMIT_IS_LOCAL_ONLY ; I did not do this in the examples, because it is a little more complicated.)

You will need a command to make a local commit from the current index / workdir; it's simple, it just calls git commit $@ -m "__LOCAL_COMMIT_ONLY__" (this is an example: the point is that it is doing something to mark that the commit is being created as local, and then canceled git commit). You will also need a command to temporarily display all local commits, execute another git command (pull, push, fetch, merge, whatever), and then reapply local commits. You will also use this command to create local commits that you intend to use, so that they always appear "under" locally only in your history.

Here is one example script that gives you both in one:

 #!/bin/sh if [[ $1 eq 'new' ]]; then shift exec git commit $@ -m "__LOCAL_COMMIT_ONLY__" elif [[ $1 eq OLD_HEAD=$(git rev-parse HEAD) OLD_REAL_HEAD="$(git rev-list --grep=__LOCAL_COMMIT_ONLY__ | tail -n1)^" git reset --soft $OLD_REAL_HEAD git $@ git rebase --onto HEAD $OLD_REAL_HEAD $OLD_HEAD 

Now, assuming you are calling the git-local script, use git local new to create a new local commit from the index (or git local new -a to create from the modified files in workdir), git local commit (the name is imperfect, sad) so that create a new "real" commit, git local push push, git local pull to pull, etc.

The main disadvantage of this is that it requires you to remember that most commands now have a prefix with local . If you forget to do this once, you will be a little excited, but not so bad - a quick git rebase -i will allow you to easily move your local commits back to the beginning, and you will start and run again. The biggest risk is that you accidentally use git push instead of git local push and git local push all your personal changes upstream, which will annoy everyone. To do this, you may need to write a small shell script to call instead of git itself (name it ~/bin/git and make sure ~/bin is in your path):

 #!/bin/bash if [[ $1 eq 'push' ]]; then if git rev-list --grep=__LOCAL_COMMIT_ONLY__ | grep -q .; then echo "Can't push with local changes still active!" echo "Try using `git local push' instead." exit 1 fi fi exec /usr/bin/git "$@" 

You can also do a pre-receive hook on a server that automatically rejects any message containing __LOCAL_COMMIT_ONLY__ in its message.

+12
Nov 18 '12 at 18:34
source share

At the previous work, everyone had their own local settings branch, on which we made our individual settings. This branch was based on master ; any topic branch has been branched settings . When the themes were ready for integration, we reinstalled them on master . This is similar to what @koljaTM offers.

 A---B---C master \ F settings \ D topic rebase --onto master settings topic A---B---C master |\ | F settings \ D topic 

When new changes hit master , we would rebase settings from master , and then reassemble any themes we worked on with settings .

Admittedly, this is not a one-step solution to “leave this floating forever,” but it is reasonably clean and simple.

+8
Nov 07 '12 at 20:01
source share

You can use a patch file that can be generated from Git.

 # git diff > local.patch 

If you want to commit, reverse patch:

 # git apply -R local.patch 

After fixing, restore the patch:

 # git apply local.patch 

You only need to make sure that only local changes are in the working tree before creating the patch file. After creating the patch file, you can add it to .gitignore so that you don't commit it.

+6
Nov 13 '12 at 19:21
source share

Assuming you have local changes in a file that does not contain other changes that need to be done, you can simply ask git to ignore the changes in this file using git update-index. In particular, you need either - non-targeted, or -skip-worktree; while they basically do the same thing (mark the file unchanged in the git index), they have some very subtle features that are well described here .

+2
Apr 10 '13 at
source share

If you are really trying to prevent forward movement, you are on the right track - use

git rebase -i

and reorder all your "personal commits" as last commits, then

git push <remotename> <latest commit SHA you want to push>:<remotebranchname>

This will push all the commits before and including the SHA you provided, but not the “personal commits” that appear after it.

+1
Nov 17 '12 at 22:21
source share

You can ignore specific files in git so that they do not fall into the remote repository. The way I do such things is to save these files locally and not paste them into the repository, ignoring them.

Here is some explanation of githior.

https://help.github.com/articles/ignoring-files

0
Nov 07 '12 at 19:39
source share

I constantly came across this problem, as a rule, with sharing IDE settings, etc. with a common code base. This is a fairly common use case that you might think that it would be allowed by now, but not yet. I do not think git can handle this the way you want.

The problem, which boils down to the point, is that you want the two checks to share the same directory. For this to work, there must be some kind of data structure that can be manipulated by the user, marking which files belong to one of the checks. And this is not a 1-1 ratio; it is wise to have some part of the file with more than one check. In all cases, you need to somehow name the various checks to maintain ambiguity. For basic sanity, you'll need the lister directory, which annotates files with its validation associations.

As a concrete illustration, consider .gitignore . This is a single file that applies to all “checks”, implying an implicitly “unique check”. In order for .gitignore work well, you will need one for each scan to distinguish between different files in each scan. However, there is no hint of such an infrastructure in git .

My "standard" way to solve such problems is to arrange things so that there is one check in the directory. I create a directory called "custom" (or the like). This directory goes to .gitignore in the parent. In the user directory, I send a check from another repository and / or another place. This means that two record all changes; which is rarely a problem in practice.

If this causes someone to crack git , add a parameter to make the "named control" and leave the existing behavior anonymous. You may have anonymous statements [0..1] and [0 .. *). Based on this, most of the other things you might want to follow are pretty natural.

0
Nov 13 '12 at 19:05
source share



All Articles